Skip to content

Commit 34e7930

Browse files
committed
chore: consolidate cache items to one location
1 parent b9c18b8 commit 34e7930

7 files changed

Lines changed: 62 additions & 63 deletions

File tree

.github/workflows/integration_tests.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ on:
55
push:
66
branches:
77
- main
8-
- dev/v3
98
paths-ignore:
109
- "**/*.md"
1110
- "**/*.jpg"

common/lib/utils/cache_map.ts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,40 @@
1414
limitations under the License.
1515
*/
1616

17-
class CacheItem<V> {
18-
readonly item: V;
19-
private readonly expirationTimeNanos: bigint;
17+
import { getTimeInNanos } from "./utils";
2018

21-
constructor(item: V, expirationTimeNanos: bigint) {
19+
export class CacheItem<V> {
20+
private readonly item: V;
21+
private _expirationTimeNs: bigint;
22+
23+
constructor(item: V, expirationTime: bigint) {
2224
this.item = item;
23-
this.expirationTimeNanos = expirationTimeNanos;
25+
this._expirationTimeNs = expirationTime;
2426
}
2527

2628
isExpired(): boolean {
27-
return process.hrtime.bigint() > this.expirationTimeNanos;
29+
if (this._expirationTimeNs <= 0) {
30+
// No expiration time.
31+
return false;
32+
}
33+
return getTimeInNanos() > this._expirationTimeNs;
34+
}
35+
36+
get(returnExpired: boolean = false): V | null {
37+
return this.isExpired() && !returnExpired ? null : this.item;
38+
}
39+
40+
updateExpiration(expirationIntervalNanos: bigint): CacheItem<V> {
41+
this._expirationTimeNs = getTimeInNanos() + expirationIntervalNanos;
42+
return this;
43+
}
44+
45+
get expirationTimeNs(): bigint {
46+
return this._expirationTimeNs;
47+
}
48+
49+
toString(): string {
50+
return `CacheItem [item=${this.item}, expirationTime=${this._expirationTimeNs}]`;
2851
}
2952
}
3053

@@ -38,7 +61,7 @@ export class CacheMap<K, V> {
3861
get(key: K, defaultItemValue?: any, itemExpirationNano?: any): V | null {
3962
const cacheItem: CacheItem<V> | undefined = this.cache.get(key);
4063
if (cacheItem && !cacheItem.isExpired()) {
41-
return cacheItem.item;
64+
return cacheItem.get();
4265
}
4366

4467
if (!defaultItemValue || !itemExpirationNano) {
@@ -74,14 +97,6 @@ export class CacheMap<K, V> {
7497
this.cache.clear();
7598
}
7699

77-
getEntries(): Map<K, V> {
78-
const entries: Map<K, V> = new Map();
79-
this.cache.forEach((v, k) => {
80-
entries.set(k, v.item);
81-
});
82-
return entries;
83-
}
84-
85100
protected cleanUp() {
86101
if (this.cleanupTimeNanos < process.hrtime.bigint()) {
87102
this.cleanupTimeNanos = process.hrtime.bigint() + this.cleanupIntervalNanos;

common/lib/utils/core_services_container.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,8 @@ export class CoreServicesContainer {
4545
// getMonitorService(): MonitorService {
4646
// return this.monitorService;
4747
// }
48+
49+
static releaseResources(): void {
50+
CoreServicesContainer.INSTANCE.storageService.releaseResources();
51+
}
4852
}

common/lib/utils/sliding_expiration_cache.ts

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,7 @@
1616

1717
import { getTimeInNanos } from "./utils";
1818
import { MapUtils } from "./map_utils";
19-
20-
class CacheItem<V> {
21-
readonly item: V;
22-
private _expirationTimeNanos: bigint;
23-
24-
constructor(item: V, expirationTimeNanos: bigint) {
25-
this.item = item;
26-
this._expirationTimeNanos = expirationTimeNanos;
27-
}
28-
29-
get expirationTimeNs(): bigint {
30-
return this._expirationTimeNanos;
31-
}
32-
33-
updateExpiration(expirationIntervalNanos: bigint): CacheItem<V> {
34-
this._expirationTimeNanos = getTimeInNanos() + expirationIntervalNanos;
35-
return this;
36-
}
37-
}
19+
import { CacheItem } from "./cache_map";
3820

3921
export class SlidingExpirationCache<K, V> {
4022
protected _cleanupIntervalNanos: bigint = BigInt(10 * 60_000_000_000); // 10 minutes
@@ -69,29 +51,29 @@ export class SlidingExpirationCache<K, V> {
6951
computeIfAbsent(key: K, mappingFunc: (key: K) => V, itemExpirationNanos: bigint): V | null {
7052
this.cleanUp();
7153
const cacheItem = MapUtils.computeIfAbsent(this.map, key, (k) => new CacheItem(mappingFunc(k), getTimeInNanos() + itemExpirationNanos));
72-
return cacheItem?.updateExpiration(itemExpirationNanos).item ?? null;
54+
return cacheItem?.updateExpiration(itemExpirationNanos).get() ?? null;
7355
}
7456

7557
putIfAbsent(key: K, value: V, itemExpirationNanos: bigint): V | null {
7658
const cacheItem = MapUtils.putIfAbsent(this.map, key, new CacheItem(value, getTimeInNanos() + itemExpirationNanos));
77-
return cacheItem?.item ?? null;
59+
return cacheItem?.get(true) ?? null;
7860
}
7961

8062
get(key: K, itemExpirationNanos?: bigint): V | undefined {
8163
this.cleanUp();
8264
const cacheItem = this.map.get(key);
83-
if (cacheItem?.item && itemExpirationNanos) {
65+
if (cacheItem?.get(true) && itemExpirationNanos) {
8466
cacheItem.updateExpiration(itemExpirationNanos);
85-
return cacheItem.item;
67+
return cacheItem.get();
8668
}
87-
return cacheItem?.item;
69+
return cacheItem?.get(true);
8870
}
8971

9072
put(key: K, value: V, itemExpirationNanos: bigint): V | null {
9173
this.cleanUp();
9274
const cacheItem = new CacheItem(value, getTimeInNanos() + itemExpirationNanos);
9375
this.map.set(key, cacheItem);
94-
return cacheItem.item;
76+
return cacheItem.get(true);
9577
}
9678

9779
remove(key: K): void {
@@ -102,15 +84,15 @@ export class SlidingExpirationCache<K, V> {
10284
removeAndDispose(key: K): void {
10385
const cacheItem = MapUtils.remove(this.map, key);
10486
if (cacheItem != null && this._itemDisposalFunc != null) {
105-
this._itemDisposalFunc(cacheItem.item);
87+
this._itemDisposalFunc(cacheItem.get(true));
10688
}
10789
}
10890

10991
removeIfExpired(key: K): void {
11092
let item;
11193
MapUtils.computeIfPresent(this.map, key, (key, cacheItem) => {
11294
if (this.shouldCleanupItem(cacheItem)) {
113-
item = cacheItem.item;
95+
item = cacheItem.get(true);
11496
return null;
11597
}
11698
return cacheItem;
@@ -123,15 +105,15 @@ export class SlidingExpirationCache<K, V> {
123105

124106
shouldCleanupItem(cacheItem: CacheItem<V>): boolean {
125107
if (this._shouldDisposeFunc != null) {
126-
return getTimeInNanos() > cacheItem.expirationTimeNs && this._shouldDisposeFunc(cacheItem.item);
108+
return cacheItem.isExpired() && this._shouldDisposeFunc(cacheItem.get(true));
127109
}
128-
return getTimeInNanos() > cacheItem.expirationTimeNs;
110+
return cacheItem.isExpired();
129111
}
130112

131113
clear(): void {
132114
for (const [key, val] of this.map.entries()) {
133115
if (val !== undefined && this._itemDisposalFunc !== undefined) {
134-
this._itemDisposalFunc(val.item);
116+
this._itemDisposalFunc(val.get());
135117
}
136118
}
137119
this.map.clear();

common/lib/utils/storage/storage_service.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ export interface StorageService {
102102
* @returns The number of items stored for the given item class
103103
*/
104104
size(itemClass: Constructor): number;
105+
106+
/**
107+
* Cleanup method to stop the cleanup interval timer.
108+
* Should be called when the service is no longer needed.
109+
*/
110+
releaseResources(): void;
105111
}
106112

107113
type CacheSupplier = () => ExpirationCache<unknown, unknown>;
@@ -129,7 +135,6 @@ export class StorageServiceImpl implements StorageService {
129135
}
130136

131137
protected removeExpiredItems(): void {
132-
logger.debug("StorageServiceImpl: Removing expired items");
133138
for (const cache of this.caches.values()) {
134139
cache.removeExpiredEntries();
135140
}
@@ -246,11 +251,7 @@ export class StorageServiceImpl implements StorageService {
246251
StorageServiceImpl.defaultCacheSuppliers.set(itemClass, supplier);
247252
}
248253

249-
/**
250-
* Cleanup method to stop the cleanup interval timer.
251-
* Should be called when the service is no longer needed.
252-
*/
253-
destroy(): void {
254+
releaseResources(): void {
254255
if (this.cleanupIntervalHandle) {
255256
clearInterval(this.cleanupIntervalHandle);
256257
this.cleanupIntervalHandle = undefined;

common/lib/wrapper_property.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,7 @@ export class WrapperProperties {
232232

233233
static readonly CLUSTER_ID = new WrapperProperty<string>(
234234
"clusterId",
235-
"A unique identifier for the cluster. " +
236-
"Connections with the same cluster id share a cluster topology cache. " +
237-
"If unspecified, a cluster id is '1'.",
235+
"A unique identifier for the cluster. Connections with the same cluster id share a cluster topology cache. If unspecified, cluster id will be '1'.",
238236
"1"
239237
);
240238

tests/unit/sliding_expiration_cache.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
import { SlidingExpirationCache } from "../../common/lib/utils/sliding_expiration_cache";
18-
import { convertNanosToMs, sleep } from "../../common/lib/utils/utils";
18+
import { convertMsToNanos, convertNanosToMs, sleep } from "../../common/lib/utils/utils";
1919
import { SlidingExpirationCacheWithCleanupTask } from "../../common/lib/utils/sliding_expiration_cache_with_cleanup_task";
2020

2121
class DisposableItem {
@@ -48,9 +48,9 @@ class AsyncDisposableItem {
4848
describe("test_sliding_expiration_cache", () => {
4949
it("test compute if absent", async () => {
5050
const target = new SlidingExpirationCache(BigInt(50_000_000));
51-
const result1 = target.computeIfAbsent(1, () => "a", BigInt(1));
51+
const result1 = target.computeIfAbsent(1, () => "a", convertMsToNanos(100));
5252
const originalItemExpiration = target.map.get(1)!.expirationTimeNs;
53-
const result2 = target.computeIfAbsent(1, () => "b", BigInt(5));
53+
const result2 = target.computeIfAbsent(1, () => "b", convertMsToNanos(500));
5454
const updatedItemExpiration = target.map.get(1)?.expirationTimeNs;
5555

5656
expect(updatedItemExpiration).toBeGreaterThan(originalItemExpiration);
@@ -59,7 +59,7 @@ describe("test_sliding_expiration_cache", () => {
5959
expect(target.get(1)).toEqual("a");
6060

6161
await sleep(700);
62-
const result3 = target.computeIfAbsent(1, () => "b", BigInt(5));
62+
const result3 = target.computeIfAbsent(1, () => "b", convertMsToNanos(500));
6363
expect(result3).toEqual("b");
6464
expect(target.get(1)).toEqual("b");
6565
});
@@ -71,19 +71,19 @@ describe("test_sliding_expiration_cache", () => {
7171
(item) => item.dispose()
7272
);
7373
const itemToRemove = new DisposableItem(true);
74-
let result = target.computeIfAbsent("itemToRemove", () => itemToRemove, BigInt(15_000_000_000));
74+
let result = target.computeIfAbsent("itemToRemove", () => itemToRemove, convertMsToNanos(15_000));
7575
expect(itemToRemove).toEqual(result);
7676

7777
const itemToCleanup = new DisposableItem(true);
78-
result = target.computeIfAbsent("itemToCleanup", () => itemToCleanup, BigInt(1));
78+
result = target.computeIfAbsent("itemToCleanup", () => itemToCleanup, convertMsToNanos(100));
7979
expect(itemToCleanup).toEqual(result);
8080

8181
const nonDisposableItem = new DisposableItem(false);
82-
result = target.computeIfAbsent("nonDisposableItem", () => nonDisposableItem, BigInt(1));
82+
result = target.computeIfAbsent("nonDisposableItem", () => nonDisposableItem, convertMsToNanos(100));
8383
expect(nonDisposableItem).toEqual(result);
8484

8585
const nonExpiredItem = new DisposableItem(true);
86-
result = target.computeIfAbsent("nonExpiredItem", () => nonExpiredItem, BigInt(15_000_000_000));
86+
result = target.computeIfAbsent("nonExpiredItem", () => nonExpiredItem, convertMsToNanos(15_000));
8787
expect(nonExpiredItem).toEqual(result);
8888

8989
await sleep(700);

0 commit comments

Comments
 (0)