Skip to content

Commit eb236df

Browse files
jabzajabza
andauthored
feat(db): FlatFile per-file request queues enhancement (#705)
* FlatFile - Replace omni-queue with queue per file. * InitialState file was no removed on wipe() Co-authored-by: Thomas Kilsby <[email protected]>
1 parent 3a622f1 commit eb236df

1 file changed

Lines changed: 39 additions & 31 deletions

File tree

src/server/db/flatfile.ts

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export class FlatFile extends StorageAPI.Async {
2424
private dir: string;
2525
private logging?: boolean;
2626
private ttl?: boolean;
27-
private requests: Promise<any>;
27+
private fileQueues: { [key: string]: Promise<any> };
2828

2929
constructor({
3030
dir,
@@ -40,14 +40,32 @@ export class FlatFile extends StorageAPI.Async {
4040
this.dir = dir;
4141
this.logging = logging || false;
4242
this.ttl = ttl || false;
43-
this.requests = Promise.resolve();
43+
this.fileQueues = {};
4444
}
4545

46-
private async request<T extends any = any>(
47-
action: () => Promise<T>
48-
): Promise<T> {
49-
this.requests = this.requests.then(action, action);
50-
return this.requests;
46+
private async chainRequest(
47+
key: string,
48+
request: () => Promise<any>
49+
): Promise<any> {
50+
if (!(key in this.fileQueues)) this.fileQueues[key] = Promise.resolve();
51+
52+
this.fileQueues[key] = this.fileQueues[key].then(request, request);
53+
return this.fileQueues[key];
54+
}
55+
56+
private async getItem<T extends any = any>(key: string): Promise<T> {
57+
return this.chainRequest(key, () => this.games.getItem(key));
58+
}
59+
60+
private async setItem<T extends any = any>(
61+
key: string,
62+
value: T
63+
): Promise<any> {
64+
return this.chainRequest(key, () => this.games.setItem(key, value));
65+
}
66+
67+
private async removeItem(key: string): Promise<void> {
68+
return this.chainRequest(key, () => this.games.removeItem(key));
5169
}
5270

5371
async connect() {
@@ -66,8 +84,7 @@ export class FlatFile extends StorageAPI.Async {
6684
// Store initial state separately for easy retrieval later.
6785
const key = InitialStateKey(gameID);
6886

69-
await this.request(() => this.games.setItem(key, opts.initialState));
70-
87+
await this.setItem(key, opts.initialState);
7188
await this.setState(gameID, opts.initialState);
7289
await this.setMetadata(gameID, opts.metadata);
7390
}
@@ -79,30 +96,22 @@ export class FlatFile extends StorageAPI.Async {
7996
let result = {} as StorageAPI.FetchFields;
8097

8198
if (opts.state) {
82-
result.state = (await this.request(() =>
83-
this.games.getItem(gameID)
84-
)) as State;
99+
result.state = (await this.getItem(gameID)) as State;
85100
}
86101

87102
if (opts.metadata) {
88103
const key = MetadataKey(gameID);
89-
result.metadata = (await this.request(() =>
90-
this.games.getItem(key)
91-
)) as Server.GameMetadata;
104+
result.metadata = (await this.getItem(key)) as Server.GameMetadata;
92105
}
93106

94107
if (opts.log) {
95108
const key = LogKey(gameID);
96-
result.log = (await this.request(() =>
97-
this.games.getItem(key)
98-
)) as LogEntry[];
109+
result.log = (await this.getItem(key)) as LogEntry[];
99110
}
100111

101112
if (opts.initialState) {
102113
const key = InitialStateKey(gameID);
103-
result.initialState = (await this.request(() =>
104-
this.games.getItem(key)
105-
)) as State;
114+
result.initialState = (await this.getItem(key)) as State;
106115
}
107116

108117
return result as StorageAPI.FetchResult<O>;
@@ -115,33 +124,32 @@ export class FlatFile extends StorageAPI.Async {
115124
async setState(id: string, state: State, deltalog?: LogEntry[]) {
116125
if (deltalog && deltalog.length > 0) {
117126
const key = LogKey(id);
118-
const log: LogEntry[] =
119-
((await this.request(() => this.games.getItem(key))) as LogEntry[]) ||
120-
[];
127+
const log: LogEntry[] = ((await this.getItem(key)) as LogEntry[]) || [];
121128

122-
await this.request(() => this.games.setItem(key, log.concat(deltalog)));
129+
await this.setItem(key, log.concat(deltalog));
123130
}
124131

125-
return await this.request(() => this.games.setItem(id, state));
132+
return await this.setItem(id, state);
126133
}
127134

128135
async setMetadata(id: string, metadata: Server.GameMetadata): Promise<void> {
129136
const key = MetadataKey(id);
130137

131-
return await this.request(() => this.games.setItem(key, metadata));
138+
return await this.setItem(key, metadata);
132139
}
133140

134141
async wipe(id: string) {
135142
var keys = await this.games.keys();
136143
if (!(keys.indexOf(id) > -1)) return;
137144

138-
await this.request(() => this.games.removeItem(id));
139-
await this.request(() => this.games.removeItem(LogKey(id)));
140-
await this.request(() => this.games.removeItem(MetadataKey(id)));
145+
await this.removeItem(id);
146+
await this.removeItem(InitialStateKey(id));
147+
await this.removeItem(LogKey(id));
148+
await this.removeItem(MetadataKey(id));
141149
}
142150

143151
async listGames(): Promise<string[]> {
144-
const keys = await this.request(() => this.games.keys());
152+
const keys = await this.games.keys();
145153
const suffix = ':metadata';
146154
return keys
147155
.filter(k => k.endsWith(suffix))

0 commit comments

Comments
 (0)