-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.ts
98 lines (87 loc) · 2.54 KB
/
main.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// deno-lint-ignore-file no-explicit-any
import { Cache } from "./cache/cache.ts";
import { PeerGetter, PeerPicker } from "./nodes/peer.ts";
// TODO:better type
// When the data doesn't exist,`Getter` will be callback
export type Getter<T> = (key: string) => T;
// Store all Group
export const AllGroups: Map<string, Group<any>> = new Map();
/**
* A cached namespace where each Group has a unique `name`
*/
export class Group<T> {
// Each Group has a unique `name` as an identifier
name: string;
// getter is called when the cache does not hit
getter: Getter<T>;
// The maximum lru allowed
maxNums?: number;
// Used to store data
cacheStore: Cache<T>;
// Distributed nodes
peers: PeerPicker<T> | undefined;
constructor(name: string, getter: Getter<T>, maxNums?: number) {
this.name = name;
if (getter == null) {
throw new Error("null getter");
}
this.getter = getter;
this.maxNums = maxNums === undefined ? 10 : maxNums;
this.cacheStore = new Cache<T>(this.maxNums);
AllGroups.set(name, this);
}
/**
* RegisterPeers registers a PeerPicker for choosing remote peer
*/
RegisterPeers(peers: PeerPicker<T>) {
if (this.peers !== undefined) {
throw Error("RegisterPeerPicker called more than once");
}
this.peers = peers;
}
/**
* If the key exists in the `cacheStore`,
* get the value from the `cacheStore`,
* otherwise call the `getter` to get the new value
*/
async Get(key: string): Promise<T> {
if (key.length === 0) throw new Error("param key is required");
const val = this.cacheStore.get(key);
if (val !== undefined) {
console.log("Camellia Cache hit!");
return val;
}
return await this.load(key);
}
private async load(key: string): Promise<T> {
if (this.peers !== undefined) {
const peer = this.peers.PickPeer(key);
if (peer !== undefined) {
return await this.getFromPeer(peer, key);
}
}
return this.getLocally(key);
}
/**
* Get value from peer
*/
private async getFromPeer(peer: PeerGetter<T>, key: string): Promise<T> {
return await peer.Get(this.name, key);
}
/**
* call the `getter` to get the new value
*/
private getLocally(key: string): T {
const locallyData = this.getter(key);
//TODO:better check typeof locallyData === T
this.cacheStore.add(key, locallyData);
return locallyData;
}
}
/**
* Returns a class Group, if the Group exists
* @param name
*/
export function GetGroup(name: string): Group<any> | undefined {
return AllGroups.get(name);
}