@global-cache/core 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/getter.d.ts +0 -1
- package/dist/server/getter.d.ts.map +1 -1
- package/dist/server/getter.js +35 -29
- package/dist/server/getter.js.map +1 -1
- package/package.json +1 -1
- package/src/server/getter.ts +38 -35
package/dist/server/getter.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getter.d.ts","sourceRoot":"","sources":["../../src/server/getter.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEtE,KAAK,eAAe,GAAG;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AACjE,KAAK,cAAc,GAAG;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAC3E,KAAK,WAAW,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AACxD,KAAK,uBAAuB,GAAG;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,YAAY,GAAG,eAAe,GAAG,cAAc,GAAG,WAAW,GAAG,uBAAuB,CAAC;AAEpG,qBAAa,MAAM;IAEf,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,iBAAiB;gBADjB,cAAc,EAAE,eAAe,EAC/B,iBAAiB,EAAE,kBAAkB;IAIzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"getter.d.ts","sourceRoot":"","sources":["../../src/server/getter.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEtE,KAAK,eAAe,GAAG;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AACjE,KAAK,cAAc,GAAG;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAC3E,KAAK,WAAW,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AACxD,KAAK,uBAAuB,GAAG;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,YAAY,GAAG,eAAe,GAAG,cAAc,GAAG,WAAW,GAAG,uBAAuB,CAAC;AAEpG,qBAAa,MAAM;IAEf,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,iBAAiB;gBADjB,cAAc,EAAE,eAAe,EAC/B,iBAAiB,EAAE,kBAAkB;IAIzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAwCxE,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,WAAW;YAIL,aAAa;YAWb,aAAa;YAwCb,aAAa;YAMb,eAAe;CAI9B"}
|
package/dist/server/getter.js
CHANGED
|
@@ -28,31 +28,21 @@ class Getter {
|
|
|
28
28
|
? this.handleComputed(valueInfo)
|
|
29
29
|
: this.handleError(valueInfo);
|
|
30
30
|
}
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const signatureMismatch = (0, sig_1.checkSignature)(key, valueInfo.sig, sig);
|
|
36
|
-
// eslint-disable-next-line max-depth
|
|
37
|
-
if (signatureMismatch) {
|
|
38
|
-
return this.handleSignatureChanged(valueInfo, sig, signatureMismatch);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
31
|
+
// no value in memory -- claim the key atomically before touching persistent storage,
|
|
32
|
+
// so concurrent callers for the same key can't all decide to recompute independently
|
|
33
|
+
if (!valueInfo) {
|
|
34
|
+
return this.handleNoValue(key, sig, ttl);
|
|
41
35
|
}
|
|
42
36
|
// check expired
|
|
43
|
-
if (valueInfo
|
|
37
|
+
if (valueInfo.state === 'computed' && valueInfo.persistent && ttl) {
|
|
44
38
|
if ((0, ttl_1.isExpired)(valueInfo.computedAt, ttl)) {
|
|
45
39
|
return this.handleExpired(valueInfo, ttl);
|
|
46
40
|
}
|
|
47
41
|
}
|
|
48
42
|
// normal cache hit
|
|
49
|
-
if (valueInfo
|
|
43
|
+
if (valueInfo.state === 'computed') {
|
|
50
44
|
return this.handleComputed(valueInfo);
|
|
51
45
|
}
|
|
52
|
-
// no value
|
|
53
|
-
if (!valueInfo) {
|
|
54
|
-
return this.handleNoValue(key, sig, ttl);
|
|
55
|
-
}
|
|
56
46
|
return this.handleDefault(valueInfo);
|
|
57
47
|
}
|
|
58
48
|
handleSignatureMismatch(key, signatureMismatch) {
|
|
@@ -64,16 +54,6 @@ class Getter {
|
|
|
64
54
|
handleError(valueInfo) {
|
|
65
55
|
return { result: 'error', message: valueInfo.errorMessage || 'Unknown error' };
|
|
66
56
|
}
|
|
67
|
-
async handleSignatureChanged(loadedValueInfo, newSig, { field }) {
|
|
68
|
-
await this.updateValueInfo(loadedValueInfo, {
|
|
69
|
-
state: 'computing',
|
|
70
|
-
sig: newSig,
|
|
71
|
-
prevValue: loadedValueInfo.value,
|
|
72
|
-
value: undefined,
|
|
73
|
-
computedAt: undefined,
|
|
74
|
-
});
|
|
75
|
-
return { result: 'cache-miss', message: `signature changed: ${field}` };
|
|
76
|
-
}
|
|
77
57
|
async handleExpired(valueInfo, ttl) {
|
|
78
58
|
await this.updateValueInfo(valueInfo, {
|
|
79
59
|
state: 'computing',
|
|
@@ -83,16 +63,42 @@ class Getter {
|
|
|
83
63
|
});
|
|
84
64
|
return { result: 'cache-miss', message: `expired: ${ttl}` };
|
|
85
65
|
}
|
|
66
|
+
// eslint-disable-next-line visual/complexity, max-statements
|
|
86
67
|
async handleNoValue(key, sig, ttl) {
|
|
87
|
-
const
|
|
88
|
-
|
|
68
|
+
const placeholder = {
|
|
69
|
+
key,
|
|
70
|
+
state: 'computing',
|
|
71
|
+
sig,
|
|
72
|
+
persistent: Boolean(ttl),
|
|
73
|
+
};
|
|
74
|
+
const claimed = this.testRunStorage.claimForComputing(placeholder);
|
|
89
75
|
if (!claimed) {
|
|
90
76
|
const resolved = await this.testRunStorage.waitForComputed(key);
|
|
91
77
|
return resolved.state === 'computed'
|
|
92
78
|
? this.handleComputed(resolved)
|
|
93
79
|
: this.handleError(resolved);
|
|
94
80
|
}
|
|
95
|
-
|
|
81
|
+
if (!ttl)
|
|
82
|
+
return { result: 'cache-miss', message: 'no cached value' };
|
|
83
|
+
// We own the 'computing' slot now, so no other concurrent caller can also decide
|
|
84
|
+
// to recompute this key while we consult persistent storage.
|
|
85
|
+
const persisted = await this.persistentStorage.load(key);
|
|
86
|
+
if (!persisted)
|
|
87
|
+
return { result: 'cache-miss', message: 'no cached value' };
|
|
88
|
+
const signatureMismatch = (0, sig_1.checkSignature)(key, persisted.sig, sig);
|
|
89
|
+
if (signatureMismatch) {
|
|
90
|
+
placeholder.prevValue = persisted.value;
|
|
91
|
+
return { result: 'cache-miss', message: `signature changed: ${signatureMismatch.field}` };
|
|
92
|
+
}
|
|
93
|
+
if ((0, ttl_1.isExpired)(persisted.computedAt, ttl)) {
|
|
94
|
+
placeholder.prevValue = persisted.value;
|
|
95
|
+
return { result: 'cache-miss', message: `expired: ${ttl}` };
|
|
96
|
+
}
|
|
97
|
+
// Persistent value is fresh and valid -- adopt it as computed, update the map entry
|
|
98
|
+
// (already resident via claimForComputing) and notify any waiters.
|
|
99
|
+
Object.assign(placeholder, persisted);
|
|
100
|
+
await this.testRunStorage.save(placeholder, { notify: true });
|
|
101
|
+
return this.handleComputed(placeholder);
|
|
96
102
|
}
|
|
97
103
|
async handleDefault(valueInfo) {
|
|
98
104
|
const message = `old state: ${valueInfo.state}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getter.js","sourceRoot":"","sources":["../../src/server/getter.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,uCAAkE;AAClE,uCAA0C;AAW1C,MAAa,MAAM;IACjB,YACU,cAA+B,EAC/B,iBAAqC;QADrC,mBAAc,GAAd,cAAc,CAAiB;QAC/B,sBAAiB,GAAjB,iBAAiB,CAAoB;IAC5C,CAAC;IAEJ,6DAA6D;IAC7D,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,GAAW,EAAE,GAAY;QAC9C,IAAI,SAAS,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEpD,+CAA+C;QAC/C,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,iBAAiB,GAAG,IAAA,oBAAc,EAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAClE,IAAI,iBAAiB,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC,uBAAuB,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAED,oBAAoB;QACpB,IAAI,SAAS,EAAE,KAAK,KAAK,WAAW,EAAE,CAAC;YACrC,SAAS,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAC3D,OAAO,SAAS,CAAC,KAAK,KAAK,UAAU;gBACnC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC;gBAChC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QAED
|
|
1
|
+
{"version":3,"file":"getter.js","sourceRoot":"","sources":["../../src/server/getter.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,uCAAkE;AAClE,uCAA0C;AAW1C,MAAa,MAAM;IACjB,YACU,cAA+B,EAC/B,iBAAqC;QADrC,mBAAc,GAAd,cAAc,CAAiB;QAC/B,sBAAiB,GAAjB,iBAAiB,CAAoB;IAC5C,CAAC;IAEJ,6DAA6D;IAC7D,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,GAAW,EAAE,GAAY;QAC9C,IAAI,SAAS,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEpD,+CAA+C;QAC/C,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,iBAAiB,GAAG,IAAA,oBAAc,EAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAClE,IAAI,iBAAiB,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC,uBAAuB,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAED,oBAAoB;QACpB,IAAI,SAAS,EAAE,KAAK,KAAK,WAAW,EAAE,CAAC;YACrC,SAAS,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAC3D,OAAO,SAAS,CAAC,KAAK,KAAK,UAAU;gBACnC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC;gBAChC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QAED,qFAAqF;QACrF,qFAAqF;QACrF,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC3C,CAAC;QAED,gBAAgB;QAChB,IAAI,SAAS,CAAC,KAAK,KAAK,UAAU,IAAI,SAAS,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;YAClE,IAAI,IAAA,eAAS,EAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE,CAAC;gBACzC,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,mBAAmB;QACnB,IAAI,SAAS,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QACxC,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAEO,uBAAuB,CAC7B,GAAW,EACX,iBAAoC;QAEpC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,mBAAmB,CAAC,GAAG,EAAE,iBAAiB,CAAC,EAAE,CAAC;IAC1F,CAAC;IAEO,cAAc,CAAC,SAA2B;QAChD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;IAC5C,CAAC;IAEO,WAAW,CAAC,SAA2B;QAC7C,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,YAAY,IAAI,eAAe,EAAE,CAAC;IACjF,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,SAA2B,EAAE,GAAW;QAClE,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE;YACpC,KAAK,EAAE,WAAW;YAClB,SAAS,EAAE,SAAS,CAAC,KAAK;YAC1B,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,SAAS;SACtB,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,GAAG,EAAE,EAAE,CAAC;IAC9D,CAAC;IAED,6DAA6D;IACrD,KAAK,CAAC,aAAa,CAAC,GAAW,EAAE,GAAW,EAAE,GAAY;QAChE,MAAM,WAAW,GAAqB;YACpC,GAAG;YACH,KAAK,EAAE,WAAW;YAClB,GAAG;YACH,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC;SACzB,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;QACnE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAChE,OAAO,QAAQ,CAAC,KAAK,KAAK,UAAU;gBAClC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC;gBAC/B,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;QAEtE,iFAAiF;QACjF,6DAA6D;QAC7D,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzD,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;QAE5E,MAAM,iBAAiB,GAAG,IAAA,oBAAc,EAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAClE,IAAI,iBAAiB,EAAE,CAAC;YACtB,WAAW,CAAC,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC;YACxC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,sBAAsB,iBAAiB,CAAC,KAAK,EAAE,EAAE,CAAC;QAC5F,CAAC;QAED,IAAI,IAAA,eAAS,EAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE,CAAC;YACzC,WAAW,CAAC,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC;YACxC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,GAAG,EAAE,EAAE,CAAC;QAC9D,CAAC;QAED,oFAAoF;QACpF,mEAAmE;QACnE,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QACtC,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IAC1C,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,SAA2B;QACrD,MAAM,OAAO,GAAG,cAAc,SAAS,CAAC,KAAK,EAAE,CAAC;QAChD,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAC9D,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;IAC3C,CAAC;IAEO,KAAK,CAAC,eAAe,CAAC,SAA2B,EAAE,KAAiC;QAC1F,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAChC,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;CACF;AA3HD,wBA2HC;AAED,SAAS,mBAAmB,CAAC,GAAW,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAqB;IACpF,OAAO;QACL,uBAAuB,KAAK,KAAK;QACjC,iDAAiD,GAAG,4BAA4B;QAChF,aAAa,KAAK,KAAK,MAAM,IAAI;QACjC,aAAa,KAAK,KAAK,MAAM,EAAE;KAChC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACb,CAAC"}
|
package/package.json
CHANGED
package/src/server/getter.ts
CHANGED
|
@@ -39,35 +39,24 @@ export class Getter {
|
|
|
39
39
|
: this.handleError(valueInfo);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const signatureMismatch = checkSignature(key, valueInfo.sig, sig);
|
|
47
|
-
// eslint-disable-next-line max-depth
|
|
48
|
-
if (signatureMismatch) {
|
|
49
|
-
return this.handleSignatureChanged(valueInfo, sig, signatureMismatch);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
42
|
+
// no value in memory -- claim the key atomically before touching persistent storage,
|
|
43
|
+
// so concurrent callers for the same key can't all decide to recompute independently
|
|
44
|
+
if (!valueInfo) {
|
|
45
|
+
return this.handleNoValue(key, sig, ttl);
|
|
52
46
|
}
|
|
53
47
|
|
|
54
48
|
// check expired
|
|
55
|
-
if (valueInfo
|
|
49
|
+
if (valueInfo.state === 'computed' && valueInfo.persistent && ttl) {
|
|
56
50
|
if (isExpired(valueInfo.computedAt, ttl)) {
|
|
57
51
|
return this.handleExpired(valueInfo, ttl);
|
|
58
52
|
}
|
|
59
53
|
}
|
|
60
54
|
|
|
61
55
|
// normal cache hit
|
|
62
|
-
if (valueInfo
|
|
56
|
+
if (valueInfo.state === 'computed') {
|
|
63
57
|
return this.handleComputed(valueInfo);
|
|
64
58
|
}
|
|
65
59
|
|
|
66
|
-
// no value
|
|
67
|
-
if (!valueInfo) {
|
|
68
|
-
return this.handleNoValue(key, sig, ttl);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
60
|
return this.handleDefault(valueInfo);
|
|
72
61
|
}
|
|
73
62
|
|
|
@@ -86,21 +75,6 @@ export class Getter {
|
|
|
86
75
|
return { result: 'error', message: valueInfo.errorMessage || 'Unknown error' };
|
|
87
76
|
}
|
|
88
77
|
|
|
89
|
-
private async handleSignatureChanged(
|
|
90
|
-
loadedValueInfo: TestRunValueInfo,
|
|
91
|
-
newSig: string,
|
|
92
|
-
{ field }: SignatureMismatch,
|
|
93
|
-
): Promise<GetterCacheMiss> {
|
|
94
|
-
await this.updateValueInfo(loadedValueInfo, {
|
|
95
|
-
state: 'computing',
|
|
96
|
-
sig: newSig,
|
|
97
|
-
prevValue: loadedValueInfo.value,
|
|
98
|
-
value: undefined,
|
|
99
|
-
computedAt: undefined,
|
|
100
|
-
});
|
|
101
|
-
return { result: 'cache-miss', message: `signature changed: ${field}` };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
78
|
private async handleExpired(valueInfo: TestRunValueInfo, ttl: number): Promise<GetterCacheMiss> {
|
|
105
79
|
await this.updateValueInfo(valueInfo, {
|
|
106
80
|
state: 'computing',
|
|
@@ -111,16 +85,45 @@ export class Getter {
|
|
|
111
85
|
return { result: 'cache-miss', message: `expired: ${ttl}` };
|
|
112
86
|
}
|
|
113
87
|
|
|
88
|
+
// eslint-disable-next-line visual/complexity, max-statements
|
|
114
89
|
private async handleNoValue(key: string, sig: string, ttl?: number): Promise<GetterResult> {
|
|
115
|
-
const
|
|
116
|
-
|
|
90
|
+
const placeholder: TestRunValueInfo = {
|
|
91
|
+
key,
|
|
92
|
+
state: 'computing',
|
|
93
|
+
sig,
|
|
94
|
+
persistent: Boolean(ttl),
|
|
95
|
+
};
|
|
96
|
+
const claimed = this.testRunStorage.claimForComputing(placeholder);
|
|
117
97
|
if (!claimed) {
|
|
118
98
|
const resolved = await this.testRunStorage.waitForComputed(key);
|
|
119
99
|
return resolved.state === 'computed'
|
|
120
100
|
? this.handleComputed(resolved)
|
|
121
101
|
: this.handleError(resolved);
|
|
122
102
|
}
|
|
123
|
-
|
|
103
|
+
|
|
104
|
+
if (!ttl) return { result: 'cache-miss', message: 'no cached value' };
|
|
105
|
+
|
|
106
|
+
// We own the 'computing' slot now, so no other concurrent caller can also decide
|
|
107
|
+
// to recompute this key while we consult persistent storage.
|
|
108
|
+
const persisted = await this.persistentStorage.load(key);
|
|
109
|
+
if (!persisted) return { result: 'cache-miss', message: 'no cached value' };
|
|
110
|
+
|
|
111
|
+
const signatureMismatch = checkSignature(key, persisted.sig, sig);
|
|
112
|
+
if (signatureMismatch) {
|
|
113
|
+
placeholder.prevValue = persisted.value;
|
|
114
|
+
return { result: 'cache-miss', message: `signature changed: ${signatureMismatch.field}` };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (isExpired(persisted.computedAt, ttl)) {
|
|
118
|
+
placeholder.prevValue = persisted.value;
|
|
119
|
+
return { result: 'cache-miss', message: `expired: ${ttl}` };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Persistent value is fresh and valid -- adopt it as computed, update the map entry
|
|
123
|
+
// (already resident via claimForComputing) and notify any waiters.
|
|
124
|
+
Object.assign(placeholder, persisted);
|
|
125
|
+
await this.testRunStorage.save(placeholder, { notify: true });
|
|
126
|
+
return this.handleComputed(placeholder);
|
|
124
127
|
}
|
|
125
128
|
|
|
126
129
|
private async handleDefault(valueInfo: TestRunValueInfo): Promise<GetterCacheMiss> {
|