@convex-dev/sharded-counter 0.1.4 → 0.1.5
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/README.md +5 -5
- package/dist/commonjs/client/index.d.ts +28 -18
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +25 -7
- package/dist/commonjs/client/index.js.map +1 -1
- package/dist/commonjs/component/public.d.ts +5 -1
- package/dist/commonjs/component/public.d.ts.map +1 -1
- package/dist/commonjs/component/public.js +15 -2
- package/dist/commonjs/component/public.js.map +1 -1
- package/dist/esm/client/index.d.ts +28 -18
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +25 -7
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/component/public.d.ts +5 -1
- package/dist/esm/component/public.d.ts.map +1 -1
- package/dist/esm/component/public.js +15 -2
- package/dist/esm/component/public.js.map +1 -1
- package/package.json +2 -2
- package/src/client/index.ts +81 -52
- package/src/component/_generated/api.d.ts +3 -2
- package/src/component/counter.test.ts +39 -7
- package/src/component/public.ts +26 -4
package/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/js/@convex-dev%2Fsharded-counter)
|
|
4
4
|
|
|
5
|
-
**Note: Convex Components are currently in beta.**
|
|
6
|
-
|
|
7
5
|
<!-- START: Include on https://convex.dev/components -->
|
|
8
6
|
|
|
9
7
|
This component adds counters to Convex. It acts as a key-value store from
|
|
@@ -101,12 +99,14 @@ await counter.add(ctx, "checkboxes", 5); // increment by 5
|
|
|
101
99
|
await counter.inc(ctx, "checkboxes"); // increment by 1
|
|
102
100
|
await counter.subtract(ctx, "checkboxes", 5); // decrement by 5
|
|
103
101
|
await counter.dec(ctx, "checkboxes"); // decrement by 1
|
|
102
|
+
await counter.reset(ctx, "checkboxes"); // reset to 0
|
|
104
103
|
|
|
105
104
|
const numCheckboxes = counter.for("checkboxes");
|
|
106
105
|
await numCheckboxes.inc(ctx); // increment
|
|
107
106
|
await numCheckboxes.dec(ctx); // decrement
|
|
108
107
|
await numCheckboxes.add(ctx, 5); // add 5
|
|
109
108
|
await numCheckboxes.subtract(ctx, 5); // subtract 5
|
|
109
|
+
await numCheckboxes.reset(ctx); // reset to 0
|
|
110
110
|
```
|
|
111
111
|
|
|
112
112
|
And you can read the counter's value in a query, mutation, or action.
|
|
@@ -145,7 +145,7 @@ Or by setting a default that applies to all keys not specified in `shards`:
|
|
|
145
145
|
```ts
|
|
146
146
|
const counter = new ShardedCounter(components.shardedCounter, {
|
|
147
147
|
shards: { checkboxes: 100 },
|
|
148
|
-
defaultShards:
|
|
148
|
+
defaultShards: 8,
|
|
149
149
|
});
|
|
150
150
|
```
|
|
151
151
|
|
|
@@ -187,7 +187,7 @@ number of shards to form an estimate. You can improve the estimate by reading
|
|
|
187
187
|
from more shards, at the cost of more contention:
|
|
188
188
|
|
|
189
189
|
```ts
|
|
190
|
-
const
|
|
190
|
+
const estimateFromThree = await counter.estimateCount(ctx, "checkboxes", 3);
|
|
191
191
|
```
|
|
192
192
|
|
|
193
193
|
If the counter was accumulated from many
|
|
@@ -261,7 +261,7 @@ async function insertUser(ctx, user) {
|
|
|
261
261
|
}
|
|
262
262
|
```
|
|
263
263
|
|
|
264
|
-
3. Register a [Trigger](
|
|
264
|
+
3. Register a [Trigger](https://www.npmjs.com/package/convex-helpers#triggers),
|
|
265
265
|
which automatically runs code when a mutation changes the
|
|
266
266
|
data in a table.
|
|
267
267
|
|
|
@@ -7,7 +7,6 @@ import { api } from "../component/_generated/api";
|
|
|
7
7
|
*/
|
|
8
8
|
export declare class ShardedCounter<ShardsKey extends string> {
|
|
9
9
|
private component;
|
|
10
|
-
private options?;
|
|
11
10
|
/**
|
|
12
11
|
* A sharded counter is a map from string -> counter, where each counter can
|
|
13
12
|
* be incremented or decremented.
|
|
@@ -24,9 +23,11 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
24
23
|
* keys not in `options.shards`.
|
|
25
24
|
*/
|
|
26
25
|
constructor(component: UseApi<typeof api>, options?: {
|
|
27
|
-
shards?: Record<ShardsKey, number
|
|
28
|
-
defaultShards?: number
|
|
29
|
-
}
|
|
26
|
+
shards?: Partial<Record<ShardsKey, number>>;
|
|
27
|
+
defaultShards?: number;
|
|
28
|
+
});
|
|
29
|
+
private shardsForKey;
|
|
30
|
+
private stickyShard;
|
|
30
31
|
/**
|
|
31
32
|
* Increase the counter for key `name` by `count`.
|
|
32
33
|
* If `count` is negative, the counter will decrease.
|
|
@@ -34,26 +35,26 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
34
35
|
* @param name The key to update the counter for.
|
|
35
36
|
* @param count The amount to increment the counter by. Defaults to 1.
|
|
36
37
|
*/
|
|
37
|
-
add<Name extends
|
|
38
|
+
add<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name, count?: number): Promise<void>;
|
|
38
39
|
/**
|
|
39
40
|
* Decrease the counter for key `name` by `count`.
|
|
40
41
|
*/
|
|
41
|
-
subtract<Name extends
|
|
42
|
+
subtract<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name, count?: number): Promise<void>;
|
|
42
43
|
/**
|
|
43
44
|
* Increment the counter for key `name` by 1.
|
|
44
45
|
*/
|
|
45
|
-
inc<Name extends
|
|
46
|
+
inc<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name): Promise<void>;
|
|
46
47
|
/**
|
|
47
48
|
* Decrement the counter for key `name` by 1.
|
|
48
49
|
*/
|
|
49
|
-
dec<Name extends
|
|
50
|
+
dec<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name): Promise<void>;
|
|
50
51
|
/**
|
|
51
52
|
* Gets the counter for key `name`.
|
|
52
53
|
*
|
|
53
54
|
* NOTE: this reads from all shards. If used in a mutation, it will contend
|
|
54
55
|
* with all mutations that update the counter for this key.
|
|
55
56
|
*/
|
|
56
|
-
count<Name extends
|
|
57
|
+
count<Name extends ShardsKey>(ctx: RunQueryCtx, name: Name): Promise<number>;
|
|
57
58
|
/**
|
|
58
59
|
* Redistribute counts evenly across the counter's shards.
|
|
59
60
|
*
|
|
@@ -66,7 +67,13 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
66
67
|
* This operation reads and writes all shards, so it can cause contention if
|
|
67
68
|
* called too often.
|
|
68
69
|
*/
|
|
69
|
-
rebalance<Name extends
|
|
70
|
+
rebalance<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Clear the counter for key `name`.
|
|
73
|
+
*
|
|
74
|
+
* @param name The key to clear the counter for.
|
|
75
|
+
*/
|
|
76
|
+
reset<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name): Promise<void>;
|
|
70
77
|
/**
|
|
71
78
|
* Estimate the count of a counter by only reading from a subset of shards,
|
|
72
79
|
* and extrapolating the total count.
|
|
@@ -78,7 +85,7 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
78
85
|
*
|
|
79
86
|
* Use this to reduce contention when reading the counter.
|
|
80
87
|
*/
|
|
81
|
-
estimateCount<Name extends
|
|
88
|
+
estimateCount<Name extends ShardsKey>(ctx: RunQueryCtx, name: Name, readFromShards?: number): Promise<number>;
|
|
82
89
|
/**
|
|
83
90
|
* Returns an object with methods to update and query the counter for key
|
|
84
91
|
* `name`. For fixed keys, you can call `counter.for("<key>")` to get methods
|
|
@@ -94,23 +101,23 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
94
101
|
* });
|
|
95
102
|
* ```
|
|
96
103
|
*/
|
|
97
|
-
for<Name extends
|
|
104
|
+
for<Name extends ShardsKey>(name: Name): {
|
|
98
105
|
/**
|
|
99
106
|
* Add `count` to the counter.
|
|
100
107
|
*/
|
|
101
|
-
add: (ctx: RunMutationCtx, count?: number) => Promise<
|
|
108
|
+
add: (ctx: RunMutationCtx, count?: number) => Promise<void>;
|
|
102
109
|
/**
|
|
103
110
|
* Subtract `count` from the counter.
|
|
104
111
|
*/
|
|
105
|
-
subtract: (ctx: RunMutationCtx, count?: number) => Promise<
|
|
112
|
+
subtract: (ctx: RunMutationCtx, count?: number) => Promise<void>;
|
|
106
113
|
/**
|
|
107
114
|
* Increment the counter by 1.
|
|
108
115
|
*/
|
|
109
|
-
inc: (ctx: RunMutationCtx) => Promise<
|
|
116
|
+
inc: (ctx: RunMutationCtx) => Promise<void>;
|
|
110
117
|
/**
|
|
111
118
|
* Decrement the counter by 1.
|
|
112
119
|
*/
|
|
113
|
-
dec: (ctx: RunMutationCtx) => Promise<
|
|
120
|
+
dec: (ctx: RunMutationCtx) => Promise<void>;
|
|
114
121
|
/**
|
|
115
122
|
* Get the current value of the counter.
|
|
116
123
|
*
|
|
@@ -118,6 +125,10 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
118
125
|
* contend with all mutations that update the counter for this key.
|
|
119
126
|
*/
|
|
120
127
|
count: (ctx: RunQueryCtx) => Promise<number>;
|
|
128
|
+
/**
|
|
129
|
+
* Reset the counter for this key.
|
|
130
|
+
*/
|
|
131
|
+
reset: (ctx: RunMutationCtx) => Promise<void>;
|
|
121
132
|
/**
|
|
122
133
|
* Redistribute counts evenly across the counter's shards.
|
|
123
134
|
*
|
|
@@ -133,8 +144,7 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
133
144
|
*/
|
|
134
145
|
estimateCount: (ctx: RunQueryCtx, readFromShards?: number) => Promise<number>;
|
|
135
146
|
};
|
|
136
|
-
trigger<Ctx extends RunMutationCtx, Name extends
|
|
137
|
-
private shardsForKey;
|
|
147
|
+
trigger<Ctx extends RunMutationCtx, Name extends ShardsKey>(name: Name): Trigger<Ctx, GenericDataModel, TableNamesInDataModel<GenericDataModel>>;
|
|
138
148
|
}
|
|
139
149
|
export type Trigger<Ctx, DataModel extends GenericDataModel, TableName extends TableNamesInDataModel<DataModel>> = (ctx: Ctx, change: Change<DataModel, TableName>) => Promise<void>;
|
|
140
150
|
export type Change<DataModel extends GenericDataModel, TableName extends TableNamesInDataModel<DataModel>> = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,MAAM,EACN,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,GAAG,EAAE,MAAM,6BAA6B,CAAC;AAElD;;;GAGG;AACH,qBAAa,cAAc,CAAC,SAAS,SAAS,MAAM;IAiBhD,OAAO,CAAC,SAAS;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export class ShardedCounter {
|
|
6
6
|
component;
|
|
7
|
-
options;
|
|
8
7
|
/**
|
|
9
8
|
* A sharded counter is a map from string -> counter, where each counter can
|
|
10
9
|
* be incremented or decremented.
|
|
@@ -22,8 +21,17 @@ export class ShardedCounter {
|
|
|
22
21
|
*/
|
|
23
22
|
constructor(component, options) {
|
|
24
23
|
this.component = component;
|
|
25
|
-
this.
|
|
24
|
+
this.stickyShard = {};
|
|
25
|
+
const defaultShards = options?.defaultShards;
|
|
26
|
+
this.shardsForKey = (name) => {
|
|
27
|
+
const explicitShards = options?.shards?.[name];
|
|
28
|
+
return explicitShards ?? defaultShards;
|
|
29
|
+
};
|
|
26
30
|
}
|
|
31
|
+
shardsForKey;
|
|
32
|
+
// Keep track of the shard for each key, so multiple mutations on the same key
|
|
33
|
+
// will use the same shard.
|
|
34
|
+
stickyShard;
|
|
27
35
|
/**
|
|
28
36
|
* Increase the counter for key `name` by `count`.
|
|
29
37
|
* If `count` is negative, the counter will decrease.
|
|
@@ -32,11 +40,13 @@ export class ShardedCounter {
|
|
|
32
40
|
* @param count The amount to increment the counter by. Defaults to 1.
|
|
33
41
|
*/
|
|
34
42
|
async add(ctx, name, count = 1) {
|
|
35
|
-
|
|
43
|
+
const shard = await ctx.runMutation(this.component.public.add, {
|
|
36
44
|
name,
|
|
37
45
|
count,
|
|
46
|
+
shard: this.stickyShard?.[name],
|
|
38
47
|
shards: this.shardsForKey(name),
|
|
39
48
|
});
|
|
49
|
+
this.stickyShard[name] = shard;
|
|
40
50
|
}
|
|
41
51
|
/**
|
|
42
52
|
* Decrease the counter for key `name` by `count`.
|
|
@@ -83,6 +93,14 @@ export class ShardedCounter {
|
|
|
83
93
|
shards: this.shardsForKey(name),
|
|
84
94
|
});
|
|
85
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Clear the counter for key `name`.
|
|
98
|
+
*
|
|
99
|
+
* @param name The key to clear the counter for.
|
|
100
|
+
*/
|
|
101
|
+
async reset(ctx, name) {
|
|
102
|
+
await ctx.runMutation(this.component.public.reset, { name });
|
|
103
|
+
}
|
|
86
104
|
/**
|
|
87
105
|
* Estimate the count of a counter by only reading from a subset of shards,
|
|
88
106
|
* and extrapolating the total count.
|
|
@@ -141,6 +159,10 @@ export class ShardedCounter {
|
|
|
141
159
|
* contend with all mutations that update the counter for this key.
|
|
142
160
|
*/
|
|
143
161
|
count: async (ctx) => this.count(ctx, name),
|
|
162
|
+
/**
|
|
163
|
+
* Reset the counter for this key.
|
|
164
|
+
*/
|
|
165
|
+
reset: async (ctx) => this.reset(ctx, name),
|
|
144
166
|
/**
|
|
145
167
|
* Redistribute counts evenly across the counter's shards.
|
|
146
168
|
*
|
|
@@ -167,9 +189,5 @@ export class ShardedCounter {
|
|
|
167
189
|
}
|
|
168
190
|
};
|
|
169
191
|
}
|
|
170
|
-
shardsForKey(name) {
|
|
171
|
-
const explicitShards = this.options?.shards?.[name];
|
|
172
|
-
return explicitShards ?? this.options?.defaultShards;
|
|
173
|
-
}
|
|
174
192
|
}
|
|
175
193
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,MAAM,OAAO,cAAc;IAiBf;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,MAAM,OAAO,cAAc;IAiBf;IAhBV;;;;;;;;;;;;;;OAcG;IACH,YACU,SAA6B,EACrC,OAGC;QAJO,cAAS,GAAT,SAAS,CAAoB;QAMrC,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,CAAC;QAC7C,IAAI,CAAC,YAAY,GAAG,CAAC,IAAe,EAAE,EAAE;YACtC,MAAM,cAAc,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;YAC/C,OAAO,cAAc,IAAI,aAAa,CAAC;QACzC,CAAC,CAAC;IACJ,CAAC;IAEO,YAAY,CAA0C;IAE9D,8EAA8E;IAC9E,2BAA2B;IACnB,WAAW,CAAyB;IAE5C;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,CACP,GAAmB,EACnB,IAAU,EACV,QAAgB,CAAC;QAEjB,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE;YAC7D,IAAI;YACJ,KAAK;YACL,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC;YAC/B,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;SAChC,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CACZ,GAAmB,EACnB,IAAU,EACV,QAAgB,CAAC;QAEjB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAyB,GAAmB,EAAE,IAAU;QAC/D,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAyB,GAAmB,EAAE,IAAU;QAC/D,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,KAAK,CAAyB,GAAgB,EAAE,IAAU;QAC9D,OAAO,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,SAAS,CAAyB,GAAmB,EAAE,IAAU;QACrE,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE;YACrD,IAAI;YACJ,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;SAChC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK,CAAyB,GAAmB,EAAE,IAAU;QACjE,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,aAAa,CACjB,GAAgB,EAChB,IAAU,EACV,iBAAyB,CAAC;QAE1B,OAAO,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa,EAAE;YAC7D,IAAI;YACJ,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;YAC/B,cAAc;SACf,CAAC,CAAC;IACL,CAAC;IACD;;;;;;;;;;;;;;OAcG;IACH,GAAG,CAAyB,IAAU;QACpC,OAAO;YACL;;eAEG;YACH,GAAG,EAAE,KAAK,EAAE,GAAmB,EAAE,QAAgB,CAAC,EAAE,EAAE,CACpD,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC;YAC5B;;eAEG;YACH,QAAQ,EAAE,KAAK,EAAE,GAAmB,EAAE,QAAgB,CAAC,EAAE,EAAE,CACzD,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC;YAC7B;;eAEG;YACH,GAAG,EAAE,KAAK,EAAE,GAAmB,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1D;;eAEG;YACH,GAAG,EAAE,KAAK,EAAE,GAAmB,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC3D;;;;;eAKG;YACH,KAAK,EAAE,KAAK,EAAE,GAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC;YACxD;;eAEG;YACH,KAAK,EAAE,KAAK,EAAE,GAAmB,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC;YAC3D;;;;;eAKG;YACH,SAAS,EAAE,KAAK,EAAE,GAAmB,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC;YACnE;;;;;eAKG;YACH,aAAa,EAAE,KAAK,EAAE,GAAgB,EAAE,iBAAyB,CAAC,EAAE,EAAE,CACpE,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,cAAc,CAAC;SAChD,CAAC;IACJ,CAAC;IACD,OAAO,CACL,IAAU;QAEV,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;YAC3B,IAAI,MAAM,CAAC,SAAS,KAAK,QAAQ,EAAE;gBACjC,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;aAC3B;iBAAM,IAAI,MAAM,CAAC,SAAS,KAAK,QAAQ,EAAE;gBACxC,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;aAC3B;QACH,CAAC,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export declare const DEFAULT_SHARD_COUNT = 16;
|
|
2
2
|
export declare const add: import("convex/server").RegisteredMutation<"public", {
|
|
3
|
+
shard?: number | undefined;
|
|
3
4
|
shards?: number | undefined;
|
|
4
5
|
name: string;
|
|
5
6
|
count: number;
|
|
6
|
-
}, Promise<
|
|
7
|
+
}, Promise<number>>;
|
|
7
8
|
export declare const count: import("convex/server").RegisteredQuery<"public", {
|
|
8
9
|
name: string;
|
|
9
10
|
}, Promise<number>>;
|
|
@@ -11,6 +12,9 @@ export declare const rebalance: import("convex/server").RegisteredMutation<"publ
|
|
|
11
12
|
shards?: number | undefined;
|
|
12
13
|
name: string;
|
|
13
14
|
}, Promise<void>>;
|
|
15
|
+
export declare const reset: import("convex/server").RegisteredMutation<"public", {
|
|
16
|
+
name: string;
|
|
17
|
+
}, Promise<void>>;
|
|
14
18
|
export declare const estimateCount: import("convex/server").RegisteredQuery<"public", {
|
|
15
19
|
shards?: number | undefined;
|
|
16
20
|
readFromShards?: number | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/component/public.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,eAAO,MAAM,GAAG
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/component/public.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,eAAO,MAAM,GAAG;;;;;mBA6Bd,CAAC;AAEH,eAAO,MAAM,KAAK;;mBAUhB,CAAC;AAEH,eAAO,MAAM,SAAS;;;iBA2BpB,CAAC;AAEH,eAAO,MAAM,KAAK;;iBAWhB,CAAC;AAEH,eAAO,MAAM,aAAa;;;;mBA2BxB,CAAC"}
|
|
@@ -5,11 +5,13 @@ export const add = mutation({
|
|
|
5
5
|
args: {
|
|
6
6
|
name: v.string(),
|
|
7
7
|
count: v.number(),
|
|
8
|
+
shard: v.optional(v.number()),
|
|
8
9
|
shards: v.optional(v.number()),
|
|
9
10
|
},
|
|
10
|
-
returns: v.
|
|
11
|
+
returns: v.number(),
|
|
11
12
|
handler: async (ctx, args) => {
|
|
12
|
-
const shard =
|
|
13
|
+
const shard = args.shard ??
|
|
14
|
+
Math.floor(Math.random() * (args.shards ?? DEFAULT_SHARD_COUNT));
|
|
13
15
|
const counter = await ctx.db
|
|
14
16
|
.query("counters")
|
|
15
17
|
.withIndex("name", (q) => q.eq("name", args.name).eq("shard", shard))
|
|
@@ -26,6 +28,7 @@ export const add = mutation({
|
|
|
26
28
|
shard,
|
|
27
29
|
});
|
|
28
30
|
}
|
|
31
|
+
return shard;
|
|
29
32
|
},
|
|
30
33
|
});
|
|
31
34
|
export const count = query({
|
|
@@ -68,6 +71,16 @@ export const rebalance = mutation({
|
|
|
68
71
|
}
|
|
69
72
|
},
|
|
70
73
|
});
|
|
74
|
+
export const reset = mutation({
|
|
75
|
+
args: { name: v.string() },
|
|
76
|
+
handler: async (ctx, args) => {
|
|
77
|
+
await ctx.db
|
|
78
|
+
.query("counters")
|
|
79
|
+
.withIndex("name", (q) => q.eq("name", args.name))
|
|
80
|
+
.collect()
|
|
81
|
+
.then((counters) => Promise.all(counters.map((c) => ctx.db.delete(c._id))));
|
|
82
|
+
},
|
|
83
|
+
});
|
|
71
84
|
export const estimateCount = query({
|
|
72
85
|
args: {
|
|
73
86
|
name: v.string(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.js","sourceRoot":"","sources":["../../../src/component/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAEtC,MAAM,CAAC,MAAM,GAAG,GAAG,QAAQ,CAAC;IAC1B,IAAI,EAAE;QACJ,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;QACjB,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;KAC/B;IACD,OAAO,EAAE,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"public.js","sourceRoot":"","sources":["../../../src/component/public.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,6 @@ import { api } from "../component/_generated/api";
|
|
|
7
7
|
*/
|
|
8
8
|
export declare class ShardedCounter<ShardsKey extends string> {
|
|
9
9
|
private component;
|
|
10
|
-
private options?;
|
|
11
10
|
/**
|
|
12
11
|
* A sharded counter is a map from string -> counter, where each counter can
|
|
13
12
|
* be incremented or decremented.
|
|
@@ -24,9 +23,11 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
24
23
|
* keys not in `options.shards`.
|
|
25
24
|
*/
|
|
26
25
|
constructor(component: UseApi<typeof api>, options?: {
|
|
27
|
-
shards?: Record<ShardsKey, number
|
|
28
|
-
defaultShards?: number
|
|
29
|
-
}
|
|
26
|
+
shards?: Partial<Record<ShardsKey, number>>;
|
|
27
|
+
defaultShards?: number;
|
|
28
|
+
});
|
|
29
|
+
private shardsForKey;
|
|
30
|
+
private stickyShard;
|
|
30
31
|
/**
|
|
31
32
|
* Increase the counter for key `name` by `count`.
|
|
32
33
|
* If `count` is negative, the counter will decrease.
|
|
@@ -34,26 +35,26 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
34
35
|
* @param name The key to update the counter for.
|
|
35
36
|
* @param count The amount to increment the counter by. Defaults to 1.
|
|
36
37
|
*/
|
|
37
|
-
add<Name extends
|
|
38
|
+
add<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name, count?: number): Promise<void>;
|
|
38
39
|
/**
|
|
39
40
|
* Decrease the counter for key `name` by `count`.
|
|
40
41
|
*/
|
|
41
|
-
subtract<Name extends
|
|
42
|
+
subtract<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name, count?: number): Promise<void>;
|
|
42
43
|
/**
|
|
43
44
|
* Increment the counter for key `name` by 1.
|
|
44
45
|
*/
|
|
45
|
-
inc<Name extends
|
|
46
|
+
inc<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name): Promise<void>;
|
|
46
47
|
/**
|
|
47
48
|
* Decrement the counter for key `name` by 1.
|
|
48
49
|
*/
|
|
49
|
-
dec<Name extends
|
|
50
|
+
dec<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name): Promise<void>;
|
|
50
51
|
/**
|
|
51
52
|
* Gets the counter for key `name`.
|
|
52
53
|
*
|
|
53
54
|
* NOTE: this reads from all shards. If used in a mutation, it will contend
|
|
54
55
|
* with all mutations that update the counter for this key.
|
|
55
56
|
*/
|
|
56
|
-
count<Name extends
|
|
57
|
+
count<Name extends ShardsKey>(ctx: RunQueryCtx, name: Name): Promise<number>;
|
|
57
58
|
/**
|
|
58
59
|
* Redistribute counts evenly across the counter's shards.
|
|
59
60
|
*
|
|
@@ -66,7 +67,13 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
66
67
|
* This operation reads and writes all shards, so it can cause contention if
|
|
67
68
|
* called too often.
|
|
68
69
|
*/
|
|
69
|
-
rebalance<Name extends
|
|
70
|
+
rebalance<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Clear the counter for key `name`.
|
|
73
|
+
*
|
|
74
|
+
* @param name The key to clear the counter for.
|
|
75
|
+
*/
|
|
76
|
+
reset<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name): Promise<void>;
|
|
70
77
|
/**
|
|
71
78
|
* Estimate the count of a counter by only reading from a subset of shards,
|
|
72
79
|
* and extrapolating the total count.
|
|
@@ -78,7 +85,7 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
78
85
|
*
|
|
79
86
|
* Use this to reduce contention when reading the counter.
|
|
80
87
|
*/
|
|
81
|
-
estimateCount<Name extends
|
|
88
|
+
estimateCount<Name extends ShardsKey>(ctx: RunQueryCtx, name: Name, readFromShards?: number): Promise<number>;
|
|
82
89
|
/**
|
|
83
90
|
* Returns an object with methods to update and query the counter for key
|
|
84
91
|
* `name`. For fixed keys, you can call `counter.for("<key>")` to get methods
|
|
@@ -94,23 +101,23 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
94
101
|
* });
|
|
95
102
|
* ```
|
|
96
103
|
*/
|
|
97
|
-
for<Name extends
|
|
104
|
+
for<Name extends ShardsKey>(name: Name): {
|
|
98
105
|
/**
|
|
99
106
|
* Add `count` to the counter.
|
|
100
107
|
*/
|
|
101
|
-
add: (ctx: RunMutationCtx, count?: number) => Promise<
|
|
108
|
+
add: (ctx: RunMutationCtx, count?: number) => Promise<void>;
|
|
102
109
|
/**
|
|
103
110
|
* Subtract `count` from the counter.
|
|
104
111
|
*/
|
|
105
|
-
subtract: (ctx: RunMutationCtx, count?: number) => Promise<
|
|
112
|
+
subtract: (ctx: RunMutationCtx, count?: number) => Promise<void>;
|
|
106
113
|
/**
|
|
107
114
|
* Increment the counter by 1.
|
|
108
115
|
*/
|
|
109
|
-
inc: (ctx: RunMutationCtx) => Promise<
|
|
116
|
+
inc: (ctx: RunMutationCtx) => Promise<void>;
|
|
110
117
|
/**
|
|
111
118
|
* Decrement the counter by 1.
|
|
112
119
|
*/
|
|
113
|
-
dec: (ctx: RunMutationCtx) => Promise<
|
|
120
|
+
dec: (ctx: RunMutationCtx) => Promise<void>;
|
|
114
121
|
/**
|
|
115
122
|
* Get the current value of the counter.
|
|
116
123
|
*
|
|
@@ -118,6 +125,10 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
118
125
|
* contend with all mutations that update the counter for this key.
|
|
119
126
|
*/
|
|
120
127
|
count: (ctx: RunQueryCtx) => Promise<number>;
|
|
128
|
+
/**
|
|
129
|
+
* Reset the counter for this key.
|
|
130
|
+
*/
|
|
131
|
+
reset: (ctx: RunMutationCtx) => Promise<void>;
|
|
121
132
|
/**
|
|
122
133
|
* Redistribute counts evenly across the counter's shards.
|
|
123
134
|
*
|
|
@@ -133,8 +144,7 @@ export declare class ShardedCounter<ShardsKey extends string> {
|
|
|
133
144
|
*/
|
|
134
145
|
estimateCount: (ctx: RunQueryCtx, readFromShards?: number) => Promise<number>;
|
|
135
146
|
};
|
|
136
|
-
trigger<Ctx extends RunMutationCtx, Name extends
|
|
137
|
-
private shardsForKey;
|
|
147
|
+
trigger<Ctx extends RunMutationCtx, Name extends ShardsKey>(name: Name): Trigger<Ctx, GenericDataModel, TableNamesInDataModel<GenericDataModel>>;
|
|
138
148
|
}
|
|
139
149
|
export type Trigger<Ctx, DataModel extends GenericDataModel, TableName extends TableNamesInDataModel<DataModel>> = (ctx: Ctx, change: Change<DataModel, TableName>) => Promise<void>;
|
|
140
150
|
export type Change<DataModel extends GenericDataModel, TableName extends TableNamesInDataModel<DataModel>> = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,MAAM,EACN,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,GAAG,EAAE,MAAM,6BAA6B,CAAC;AAElD;;;GAGG;AACH,qBAAa,cAAc,CAAC,SAAS,SAAS,MAAM;IAiBhD,OAAO,CAAC,SAAS;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/client/index.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export class ShardedCounter {
|
|
6
6
|
component;
|
|
7
|
-
options;
|
|
8
7
|
/**
|
|
9
8
|
* A sharded counter is a map from string -> counter, where each counter can
|
|
10
9
|
* be incremented or decremented.
|
|
@@ -22,8 +21,17 @@ export class ShardedCounter {
|
|
|
22
21
|
*/
|
|
23
22
|
constructor(component, options) {
|
|
24
23
|
this.component = component;
|
|
25
|
-
this.
|
|
24
|
+
this.stickyShard = {};
|
|
25
|
+
const defaultShards = options?.defaultShards;
|
|
26
|
+
this.shardsForKey = (name) => {
|
|
27
|
+
const explicitShards = options?.shards?.[name];
|
|
28
|
+
return explicitShards ?? defaultShards;
|
|
29
|
+
};
|
|
26
30
|
}
|
|
31
|
+
shardsForKey;
|
|
32
|
+
// Keep track of the shard for each key, so multiple mutations on the same key
|
|
33
|
+
// will use the same shard.
|
|
34
|
+
stickyShard;
|
|
27
35
|
/**
|
|
28
36
|
* Increase the counter for key `name` by `count`.
|
|
29
37
|
* If `count` is negative, the counter will decrease.
|
|
@@ -32,11 +40,13 @@ export class ShardedCounter {
|
|
|
32
40
|
* @param count The amount to increment the counter by. Defaults to 1.
|
|
33
41
|
*/
|
|
34
42
|
async add(ctx, name, count = 1) {
|
|
35
|
-
|
|
43
|
+
const shard = await ctx.runMutation(this.component.public.add, {
|
|
36
44
|
name,
|
|
37
45
|
count,
|
|
46
|
+
shard: this.stickyShard?.[name],
|
|
38
47
|
shards: this.shardsForKey(name),
|
|
39
48
|
});
|
|
49
|
+
this.stickyShard[name] = shard;
|
|
40
50
|
}
|
|
41
51
|
/**
|
|
42
52
|
* Decrease the counter for key `name` by `count`.
|
|
@@ -83,6 +93,14 @@ export class ShardedCounter {
|
|
|
83
93
|
shards: this.shardsForKey(name),
|
|
84
94
|
});
|
|
85
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Clear the counter for key `name`.
|
|
98
|
+
*
|
|
99
|
+
* @param name The key to clear the counter for.
|
|
100
|
+
*/
|
|
101
|
+
async reset(ctx, name) {
|
|
102
|
+
await ctx.runMutation(this.component.public.reset, { name });
|
|
103
|
+
}
|
|
86
104
|
/**
|
|
87
105
|
* Estimate the count of a counter by only reading from a subset of shards,
|
|
88
106
|
* and extrapolating the total count.
|
|
@@ -141,6 +159,10 @@ export class ShardedCounter {
|
|
|
141
159
|
* contend with all mutations that update the counter for this key.
|
|
142
160
|
*/
|
|
143
161
|
count: async (ctx) => this.count(ctx, name),
|
|
162
|
+
/**
|
|
163
|
+
* Reset the counter for this key.
|
|
164
|
+
*/
|
|
165
|
+
reset: async (ctx) => this.reset(ctx, name),
|
|
144
166
|
/**
|
|
145
167
|
* Redistribute counts evenly across the counter's shards.
|
|
146
168
|
*
|
|
@@ -167,9 +189,5 @@ export class ShardedCounter {
|
|
|
167
189
|
}
|
|
168
190
|
};
|
|
169
191
|
}
|
|
170
|
-
shardsForKey(name) {
|
|
171
|
-
const explicitShards = this.options?.shards?.[name];
|
|
172
|
-
return explicitShards ?? this.options?.defaultShards;
|
|
173
|
-
}
|
|
174
192
|
}
|
|
175
193
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,MAAM,OAAO,cAAc;IAiBf;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export declare const DEFAULT_SHARD_COUNT = 16;
|
|
2
2
|
export declare const add: import("convex/server").RegisteredMutation<"public", {
|
|
3
|
+
shard?: number | undefined;
|
|
3
4
|
shards?: number | undefined;
|
|
4
5
|
name: string;
|
|
5
6
|
count: number;
|
|
6
|
-
}, Promise<
|
|
7
|
+
}, Promise<number>>;
|
|
7
8
|
export declare const count: import("convex/server").RegisteredQuery<"public", {
|
|
8
9
|
name: string;
|
|
9
10
|
}, Promise<number>>;
|
|
@@ -11,6 +12,9 @@ export declare const rebalance: import("convex/server").RegisteredMutation<"publ
|
|
|
11
12
|
shards?: number | undefined;
|
|
12
13
|
name: string;
|
|
13
14
|
}, Promise<void>>;
|
|
15
|
+
export declare const reset: import("convex/server").RegisteredMutation<"public", {
|
|
16
|
+
name: string;
|
|
17
|
+
}, Promise<void>>;
|
|
14
18
|
export declare const estimateCount: import("convex/server").RegisteredQuery<"public", {
|
|
15
19
|
shards?: number | undefined;
|
|
16
20
|
readFromShards?: number | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/component/public.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,eAAO,MAAM,GAAG
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/component/public.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,eAAO,MAAM,GAAG;;;;;mBA6Bd,CAAC;AAEH,eAAO,MAAM,KAAK;;mBAUhB,CAAC;AAEH,eAAO,MAAM,SAAS;;;iBA2BpB,CAAC;AAEH,eAAO,MAAM,KAAK;;iBAWhB,CAAC;AAEH,eAAO,MAAM,aAAa;;;;mBA2BxB,CAAC"}
|
|
@@ -5,11 +5,13 @@ export const add = mutation({
|
|
|
5
5
|
args: {
|
|
6
6
|
name: v.string(),
|
|
7
7
|
count: v.number(),
|
|
8
|
+
shard: v.optional(v.number()),
|
|
8
9
|
shards: v.optional(v.number()),
|
|
9
10
|
},
|
|
10
|
-
returns: v.
|
|
11
|
+
returns: v.number(),
|
|
11
12
|
handler: async (ctx, args) => {
|
|
12
|
-
const shard =
|
|
13
|
+
const shard = args.shard ??
|
|
14
|
+
Math.floor(Math.random() * (args.shards ?? DEFAULT_SHARD_COUNT));
|
|
13
15
|
const counter = await ctx.db
|
|
14
16
|
.query("counters")
|
|
15
17
|
.withIndex("name", (q) => q.eq("name", args.name).eq("shard", shard))
|
|
@@ -26,6 +28,7 @@ export const add = mutation({
|
|
|
26
28
|
shard,
|
|
27
29
|
});
|
|
28
30
|
}
|
|
31
|
+
return shard;
|
|
29
32
|
},
|
|
30
33
|
});
|
|
31
34
|
export const count = query({
|
|
@@ -68,6 +71,16 @@ export const rebalance = mutation({
|
|
|
68
71
|
}
|
|
69
72
|
},
|
|
70
73
|
});
|
|
74
|
+
export const reset = mutation({
|
|
75
|
+
args: { name: v.string() },
|
|
76
|
+
handler: async (ctx, args) => {
|
|
77
|
+
await ctx.db
|
|
78
|
+
.query("counters")
|
|
79
|
+
.withIndex("name", (q) => q.eq("name", args.name))
|
|
80
|
+
.collect()
|
|
81
|
+
.then((counters) => Promise.all(counters.map((c) => ctx.db.delete(c._id))));
|
|
82
|
+
},
|
|
83
|
+
});
|
|
71
84
|
export const estimateCount = query({
|
|
72
85
|
args: {
|
|
73
86
|
name: v.string(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.js","sourceRoot":"","sources":["../../../src/component/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAEtC,MAAM,CAAC,MAAM,GAAG,GAAG,QAAQ,CAAC;IAC1B,IAAI,EAAE;QACJ,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;QACjB,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;KAC/B;IACD,OAAO,EAAE,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"public.js","sourceRoot":"","sources":["../../../src/component/public.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"email": "support@convex.dev",
|
|
8
8
|
"url": "https://github.com/get-convex/sharded-counter/issues"
|
|
9
9
|
},
|
|
10
|
-
"version": "0.1.
|
|
10
|
+
"version": "0.1.5",
|
|
11
11
|
"license": "Apache-2.0",
|
|
12
12
|
"keywords": [
|
|
13
13
|
"convex",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dev": "cd example; npm run dev",
|
|
23
23
|
"typecheck": "tsc --noEmit",
|
|
24
24
|
"prepare": "npm run build",
|
|
25
|
-
"test": "vitest
|
|
25
|
+
"test": "vitest",
|
|
26
26
|
"test:debug": "vitest --inspect-brk --no-file-parallelism",
|
|
27
27
|
"test:coverage": "vitest run --coverage --coverage.reporter=text"
|
|
28
28
|
},
|
package/src/client/index.ts
CHANGED
|
@@ -18,13 +18,13 @@ export class ShardedCounter<ShardsKey extends string> {
|
|
|
18
18
|
/**
|
|
19
19
|
* A sharded counter is a map from string -> counter, where each counter can
|
|
20
20
|
* be incremented or decremented.
|
|
21
|
-
*
|
|
21
|
+
*
|
|
22
22
|
* The counter is sharded into multiple documents to allow for higher
|
|
23
23
|
* throughput of updates. The default number of shards is 16.
|
|
24
|
-
*
|
|
24
|
+
*
|
|
25
25
|
* - More shards => higher throughput of updates.
|
|
26
26
|
* - Fewer shards => lower latency when querying the counter.
|
|
27
|
-
*
|
|
27
|
+
*
|
|
28
28
|
* @param options.shards The number of shards for each counter, for fixed
|
|
29
29
|
* keys.
|
|
30
30
|
* @param options.defaultShards The number of shards for each counter, for
|
|
@@ -32,93 +32,121 @@ export class ShardedCounter<ShardsKey extends string> {
|
|
|
32
32
|
*/
|
|
33
33
|
constructor(
|
|
34
34
|
private component: UseApi<typeof api>,
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
options?: {
|
|
36
|
+
shards?: Partial<Record<ShardsKey, number>>;
|
|
37
|
+
defaultShards?: number;
|
|
38
|
+
},
|
|
39
|
+
) {
|
|
40
|
+
this.stickyShard = {};
|
|
41
|
+
const defaultShards = options?.defaultShards;
|
|
42
|
+
this.shardsForKey = (name: ShardsKey) => {
|
|
43
|
+
const explicitShards = options?.shards?.[name];
|
|
44
|
+
return explicitShards ?? defaultShards;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private shardsForKey: (name: ShardsKey) => number | undefined;
|
|
49
|
+
|
|
50
|
+
// Keep track of the shard for each key, so multiple mutations on the same key
|
|
51
|
+
// will use the same shard.
|
|
52
|
+
private stickyShard: Record<string, number>;
|
|
53
|
+
|
|
37
54
|
/**
|
|
38
55
|
* Increase the counter for key `name` by `count`.
|
|
39
56
|
* If `count` is negative, the counter will decrease.
|
|
40
|
-
*
|
|
57
|
+
*
|
|
41
58
|
* @param name The key to update the counter for.
|
|
42
59
|
* @param count The amount to increment the counter by. Defaults to 1.
|
|
43
60
|
*/
|
|
44
|
-
async add<Name extends
|
|
61
|
+
async add<Name extends ShardsKey>(
|
|
45
62
|
ctx: RunMutationCtx,
|
|
46
63
|
name: Name,
|
|
47
|
-
count: number = 1
|
|
64
|
+
count: number = 1,
|
|
48
65
|
) {
|
|
49
|
-
|
|
66
|
+
const shard = await ctx.runMutation(this.component.public.add, {
|
|
50
67
|
name,
|
|
51
68
|
count,
|
|
69
|
+
shard: this.stickyShard?.[name],
|
|
52
70
|
shards: this.shardsForKey(name),
|
|
53
71
|
});
|
|
72
|
+
this.stickyShard[name] = shard;
|
|
54
73
|
}
|
|
74
|
+
|
|
55
75
|
/**
|
|
56
76
|
* Decrease the counter for key `name` by `count`.
|
|
57
77
|
*/
|
|
58
|
-
async subtract<Name extends
|
|
78
|
+
async subtract<Name extends ShardsKey>(
|
|
59
79
|
ctx: RunMutationCtx,
|
|
60
80
|
name: Name,
|
|
61
|
-
count: number = 1
|
|
81
|
+
count: number = 1,
|
|
62
82
|
) {
|
|
63
83
|
return this.add(ctx, name, -count);
|
|
64
84
|
}
|
|
85
|
+
|
|
65
86
|
/**
|
|
66
87
|
* Increment the counter for key `name` by 1.
|
|
67
88
|
*/
|
|
68
|
-
async inc<Name extends
|
|
89
|
+
async inc<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name) {
|
|
69
90
|
return this.add(ctx, name, 1);
|
|
70
91
|
}
|
|
92
|
+
|
|
71
93
|
/**
|
|
72
94
|
* Decrement the counter for key `name` by 1.
|
|
73
95
|
*/
|
|
74
|
-
async dec<Name extends
|
|
96
|
+
async dec<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name) {
|
|
75
97
|
return this.add(ctx, name, -1);
|
|
76
98
|
}
|
|
99
|
+
|
|
77
100
|
/**
|
|
78
101
|
* Gets the counter for key `name`.
|
|
79
102
|
*
|
|
80
103
|
* NOTE: this reads from all shards. If used in a mutation, it will contend
|
|
81
104
|
* with all mutations that update the counter for this key.
|
|
82
105
|
*/
|
|
83
|
-
async count<Name extends
|
|
84
|
-
ctx: RunQueryCtx,
|
|
85
|
-
name: Name
|
|
86
|
-
) {
|
|
106
|
+
async count<Name extends ShardsKey>(ctx: RunQueryCtx, name: Name) {
|
|
87
107
|
return ctx.runQuery(this.component.public.count, { name });
|
|
88
108
|
}
|
|
109
|
+
|
|
89
110
|
/**
|
|
90
111
|
* Redistribute counts evenly across the counter's shards.
|
|
91
|
-
*
|
|
112
|
+
*
|
|
92
113
|
* If there were more shards for this counter at some point, those shards
|
|
93
114
|
* will be removed.
|
|
94
|
-
*
|
|
115
|
+
*
|
|
95
116
|
* If there were fewer shards for this counter, or if the random distribution
|
|
96
117
|
* of counts is uneven, the counts will be redistributed evenly.
|
|
97
|
-
*
|
|
118
|
+
*
|
|
98
119
|
* This operation reads and writes all shards, so it can cause contention if
|
|
99
120
|
* called too often.
|
|
100
121
|
*/
|
|
101
|
-
async rebalance<Name extends
|
|
102
|
-
ctx: RunMutationCtx,
|
|
103
|
-
name: Name,
|
|
104
|
-
) {
|
|
122
|
+
async rebalance<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name) {
|
|
105
123
|
await ctx.runMutation(this.component.public.rebalance, {
|
|
106
124
|
name,
|
|
107
125
|
shards: this.shardsForKey(name),
|
|
108
126
|
});
|
|
109
127
|
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Clear the counter for key `name`.
|
|
131
|
+
*
|
|
132
|
+
* @param name The key to clear the counter for.
|
|
133
|
+
*/
|
|
134
|
+
async reset<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name) {
|
|
135
|
+
await ctx.runMutation(this.component.public.reset, { name });
|
|
136
|
+
}
|
|
137
|
+
|
|
110
138
|
/**
|
|
111
139
|
* Estimate the count of a counter by only reading from a subset of shards,
|
|
112
140
|
* and extrapolating the total count.
|
|
113
|
-
*
|
|
141
|
+
*
|
|
114
142
|
* After a `rebalance`, or if there were a lot of data points to yield a
|
|
115
143
|
* random distribution across shards, this should be a good approximation of
|
|
116
144
|
* the total count. If there are few data points, which are not evenly
|
|
117
145
|
* distributed across shards, this will be a poor approximation.
|
|
118
|
-
*
|
|
146
|
+
*
|
|
119
147
|
* Use this to reduce contention when reading the counter.
|
|
120
148
|
*/
|
|
121
|
-
async estimateCount<Name extends
|
|
149
|
+
async estimateCount<Name extends ShardsKey>(
|
|
122
150
|
ctx: RunQueryCtx,
|
|
123
151
|
name: Name,
|
|
124
152
|
readFromShards: number = 1,
|
|
@@ -144,7 +172,7 @@ export class ShardedCounter<ShardsKey extends string> {
|
|
|
144
172
|
* });
|
|
145
173
|
* ```
|
|
146
174
|
*/
|
|
147
|
-
for<Name extends
|
|
175
|
+
for<Name extends ShardsKey>(name: Name) {
|
|
148
176
|
return {
|
|
149
177
|
/**
|
|
150
178
|
* Add `count` to the counter.
|
|
@@ -166,14 +194,18 @@ export class ShardedCounter<ShardsKey extends string> {
|
|
|
166
194
|
dec: async (ctx: RunMutationCtx) => this.add(ctx, name, -1),
|
|
167
195
|
/**
|
|
168
196
|
* Get the current value of the counter.
|
|
169
|
-
*
|
|
197
|
+
*
|
|
170
198
|
* NOTE: this reads from all shards. If used in a mutation, it will
|
|
171
199
|
* contend with all mutations that update the counter for this key.
|
|
172
200
|
*/
|
|
173
201
|
count: async (ctx: RunQueryCtx) => this.count(ctx, name),
|
|
202
|
+
/**
|
|
203
|
+
* Reset the counter for this key.
|
|
204
|
+
*/
|
|
205
|
+
reset: async (ctx: RunMutationCtx) => this.reset(ctx, name),
|
|
174
206
|
/**
|
|
175
207
|
* Redistribute counts evenly across the counter's shards.
|
|
176
|
-
*
|
|
208
|
+
*
|
|
177
209
|
* This operation reads and writes all shards, so it can cause contention
|
|
178
210
|
* if called too often.
|
|
179
211
|
*/
|
|
@@ -181,17 +213,14 @@ export class ShardedCounter<ShardsKey extends string> {
|
|
|
181
213
|
/**
|
|
182
214
|
* Estimate the counter by only reading from a subset of shards,
|
|
183
215
|
* and extrapolating the total count.
|
|
184
|
-
*
|
|
216
|
+
*
|
|
185
217
|
* Use this to reduce contention when reading the counter.
|
|
186
218
|
*/
|
|
187
219
|
estimateCount: async (ctx: RunQueryCtx, readFromShards: number = 1) =>
|
|
188
220
|
this.estimateCount(ctx, name, readFromShards),
|
|
189
221
|
};
|
|
190
222
|
}
|
|
191
|
-
trigger<
|
|
192
|
-
Ctx extends RunMutationCtx,
|
|
193
|
-
Name extends string = ShardsKey,
|
|
194
|
-
>(
|
|
223
|
+
trigger<Ctx extends RunMutationCtx, Name extends ShardsKey>(
|
|
195
224
|
name: Name,
|
|
196
225
|
): Trigger<Ctx, GenericDataModel, TableNamesInDataModel<GenericDataModel>> {
|
|
197
226
|
return async (ctx, change) => {
|
|
@@ -202,10 +231,6 @@ export class ShardedCounter<ShardsKey extends string> {
|
|
|
202
231
|
}
|
|
203
232
|
};
|
|
204
233
|
}
|
|
205
|
-
private shardsForKey<Name extends string = ShardsKey>(name: Name) {
|
|
206
|
-
const explicitShards = this.options?.shards?.[name as string as ShardsKey];
|
|
207
|
-
return explicitShards ?? this.options?.defaultShards;
|
|
208
|
-
}
|
|
209
234
|
}
|
|
210
235
|
|
|
211
236
|
/* Type utils follow */
|
|
@@ -221,19 +246,23 @@ export type Change<
|
|
|
221
246
|
TableName extends TableNamesInDataModel<DataModel>,
|
|
222
247
|
> = {
|
|
223
248
|
id: GenericId<TableName>;
|
|
224
|
-
} & (
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
249
|
+
} & (
|
|
250
|
+
| {
|
|
251
|
+
operation: "insert";
|
|
252
|
+
oldDoc: null;
|
|
253
|
+
newDoc: DocumentByName<DataModel, TableName>;
|
|
254
|
+
}
|
|
255
|
+
| {
|
|
256
|
+
operation: "update";
|
|
257
|
+
oldDoc: DocumentByName<DataModel, TableName>;
|
|
258
|
+
newDoc: DocumentByName<DataModel, TableName>;
|
|
259
|
+
}
|
|
260
|
+
| {
|
|
261
|
+
operation: "delete";
|
|
262
|
+
oldDoc: DocumentByName<DataModel, TableName>;
|
|
263
|
+
newDoc: null;
|
|
264
|
+
}
|
|
265
|
+
);
|
|
237
266
|
|
|
238
267
|
type RunQueryCtx = {
|
|
239
268
|
runQuery: GenericQueryCtx<GenericDataModel>["runQuery"];
|
|
@@ -31,8 +31,8 @@ export type Mounts = {
|
|
|
31
31
|
add: FunctionReference<
|
|
32
32
|
"mutation",
|
|
33
33
|
"public",
|
|
34
|
-
{ count: number; name: string; shards?: number },
|
|
35
|
-
|
|
34
|
+
{ count: number; name: string; shard?: number; shards?: number },
|
|
35
|
+
number
|
|
36
36
|
>;
|
|
37
37
|
count: FunctionReference<"query", "public", { name: string }, number>;
|
|
38
38
|
estimateCount: FunctionReference<
|
|
@@ -47,6 +47,7 @@ export type Mounts = {
|
|
|
47
47
|
{ name: string; shards?: number },
|
|
48
48
|
any
|
|
49
49
|
>;
|
|
50
|
+
reset: FunctionReference<"mutation", "public", { name: string }, any>;
|
|
50
51
|
};
|
|
51
52
|
};
|
|
52
53
|
// For now fullApiWithMounts is only fullApi which provides
|
|
@@ -22,14 +22,39 @@ describe("counter", () => {
|
|
|
22
22
|
expect(await t.query(api.public.count, { name: "beans" })).toEqual(10);
|
|
23
23
|
expect(await t.query(api.public.count, { name: "friends" })).toEqual(11);
|
|
24
24
|
});
|
|
25
|
+
test("respects shard argument", async () => {
|
|
26
|
+
const t = convexTest(schema, modules);
|
|
27
|
+
await t.mutation(api.public.add, { name: "beans", count: 10, shard: 1 });
|
|
28
|
+
await t.mutation(api.public.add, { name: "beans", count: 5, shard: 2 });
|
|
29
|
+
const values = await t.run(async (ctx) => {
|
|
30
|
+
const shard1 = await ctx.db
|
|
31
|
+
.query("counters")
|
|
32
|
+
.withIndex("name", (q) => q.eq("name", "beans").eq("shard", 1))
|
|
33
|
+
.unique();
|
|
34
|
+
const shard2 = await ctx.db
|
|
35
|
+
.query("counters")
|
|
36
|
+
.withIndex("name", (q) => q.eq("name", "beans").eq("shard", 2))
|
|
37
|
+
.unique();
|
|
38
|
+
return [shard1?.value, shard2?.value];
|
|
39
|
+
});
|
|
40
|
+
expect(values).toEqual([10, 5]);
|
|
41
|
+
});
|
|
42
|
+
test("reset", async () => {
|
|
43
|
+
const t = convexTest(schema, modules);
|
|
44
|
+
await t.mutation(api.public.add, { name: "beans", count: 10 });
|
|
45
|
+
await t.mutation(api.public.reset, { name: "beans" });
|
|
46
|
+
expect(await t.query(api.public.count, { name: "beans" })).toEqual(0);
|
|
47
|
+
});
|
|
25
48
|
});
|
|
26
49
|
|
|
27
50
|
fcTest.prop({
|
|
28
|
-
updates: fc.array(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
51
|
+
updates: fc.array(
|
|
52
|
+
fc.record({
|
|
53
|
+
v: fc.integer({ min: -10000, max: 10000 }).map((i) => i / 100),
|
|
54
|
+
key: fc.string(),
|
|
55
|
+
shards: fc.option(fc.integer({ min: 1, max: 100 })),
|
|
56
|
+
}),
|
|
57
|
+
),
|
|
33
58
|
})(
|
|
34
59
|
"updates to counter should match in-memory counter which ignores sharding",
|
|
35
60
|
async ({ updates }) => {
|
|
@@ -37,7 +62,11 @@ fcTest.prop({
|
|
|
37
62
|
const counter = new Map<string, number>();
|
|
38
63
|
for (const { v, key, shards } of updates) {
|
|
39
64
|
counter.set(key, (counter.get(key) ?? 0) + v);
|
|
40
|
-
await t.mutation(api.public.add, {
|
|
65
|
+
await t.mutation(api.public.add, {
|
|
66
|
+
name: key,
|
|
67
|
+
count: v,
|
|
68
|
+
shards: shards ?? undefined,
|
|
69
|
+
});
|
|
41
70
|
const count = await t.query(api.public.count, { name: key });
|
|
42
71
|
expect(count).toBeCloseTo(counter.get(key)!);
|
|
43
72
|
}
|
|
@@ -47,7 +76,10 @@ fcTest.prop({
|
|
|
47
76
|
const count = await t.query(api.public.count, { name: key });
|
|
48
77
|
expect(count).toBeCloseTo(value);
|
|
49
78
|
for (let i = 1; i <= 16; i++) {
|
|
50
|
-
const estimate = await t.query(api.public.estimateCount, {
|
|
79
|
+
const estimate = await t.query(api.public.estimateCount, {
|
|
80
|
+
name: key,
|
|
81
|
+
readFromShards: i,
|
|
82
|
+
});
|
|
51
83
|
expect(estimate).toBeCloseTo(value);
|
|
52
84
|
}
|
|
53
85
|
}
|
package/src/component/public.ts
CHANGED
|
@@ -7,11 +7,14 @@ export const add = mutation({
|
|
|
7
7
|
args: {
|
|
8
8
|
name: v.string(),
|
|
9
9
|
count: v.number(),
|
|
10
|
+
shard: v.optional(v.number()),
|
|
10
11
|
shards: v.optional(v.number()),
|
|
11
12
|
},
|
|
12
|
-
returns: v.
|
|
13
|
+
returns: v.number(),
|
|
13
14
|
handler: async (ctx, args) => {
|
|
14
|
-
const shard =
|
|
15
|
+
const shard =
|
|
16
|
+
args.shard ??
|
|
17
|
+
Math.floor(Math.random() * (args.shards ?? DEFAULT_SHARD_COUNT));
|
|
15
18
|
const counter = await ctx.db
|
|
16
19
|
.query("counters")
|
|
17
20
|
.withIndex("name", (q) => q.eq("name", args.name).eq("shard", shard))
|
|
@@ -27,6 +30,7 @@ export const add = mutation({
|
|
|
27
30
|
shard,
|
|
28
31
|
});
|
|
29
32
|
}
|
|
33
|
+
return shard;
|
|
30
34
|
},
|
|
31
35
|
});
|
|
32
36
|
|
|
@@ -71,6 +75,19 @@ export const rebalance = mutation({
|
|
|
71
75
|
},
|
|
72
76
|
});
|
|
73
77
|
|
|
78
|
+
export const reset = mutation({
|
|
79
|
+
args: { name: v.string() },
|
|
80
|
+
handler: async (ctx, args) => {
|
|
81
|
+
await ctx.db
|
|
82
|
+
.query("counters")
|
|
83
|
+
.withIndex("name", (q) => q.eq("name", args.name))
|
|
84
|
+
.collect()
|
|
85
|
+
.then((counters) =>
|
|
86
|
+
Promise.all(counters.map((c) => ctx.db.delete(c._id))),
|
|
87
|
+
);
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
74
91
|
export const estimateCount = query({
|
|
75
92
|
args: {
|
|
76
93
|
name: v.string(),
|
|
@@ -79,8 +96,13 @@ export const estimateCount = query({
|
|
|
79
96
|
},
|
|
80
97
|
handler: async (ctx, args) => {
|
|
81
98
|
const shardCount = args.shards ?? DEFAULT_SHARD_COUNT;
|
|
82
|
-
const readFromShards = Math.min(
|
|
83
|
-
|
|
99
|
+
const readFromShards = Math.min(
|
|
100
|
+
Math.max(1, args.readFromShards ?? 1),
|
|
101
|
+
shardCount,
|
|
102
|
+
);
|
|
103
|
+
const shards = shuffle(
|
|
104
|
+
Array.from({ length: shardCount }, (_, i) => i),
|
|
105
|
+
).slice(0, readFromShards);
|
|
84
106
|
let readCount = 0;
|
|
85
107
|
for (const shard of shards) {
|
|
86
108
|
const counter = await ctx.db
|