@convex-dev/sharded-counter 0.1.3 → 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 +136 -7
- package/dist/commonjs/client/index.d.ts +96 -13
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +108 -5
- package/dist/commonjs/client/index.js.map +1 -1
- package/dist/commonjs/component/_generated/api.d.ts.map +1 -1
- package/dist/commonjs/component/_generated/api.js +0 -2
- package/dist/commonjs/component/_generated/api.js.map +1 -1
- package/dist/commonjs/component/_generated/server.d.ts.map +1 -1
- package/dist/commonjs/component/_generated/server.js +0 -2
- package/dist/commonjs/component/_generated/server.js.map +1 -1
- package/dist/commonjs/component/public.d.ts +14 -1
- package/dist/commonjs/component/public.d.ts.map +1 -1
- package/dist/commonjs/component/public.js +75 -2
- package/dist/commonjs/component/public.js.map +1 -1
- package/dist/esm/client/index.d.ts +96 -13
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +108 -5
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/component/_generated/api.d.ts.map +1 -1
- package/dist/esm/component/_generated/api.js +0 -2
- package/dist/esm/component/_generated/api.js.map +1 -1
- package/dist/esm/component/_generated/server.d.ts.map +1 -1
- package/dist/esm/component/_generated/server.js +0 -2
- package/dist/esm/component/_generated/server.js.map +1 -1
- package/dist/esm/component/public.d.ts +14 -1
- package/dist/esm/component/public.d.ts.map +1 -1
- package/dist/esm/component/public.js +75 -2
- package/dist/esm/component/public.js.map +1 -1
- package/package.json +2 -2
- package/src/client/index.ts +174 -17
- package/src/component/_generated/api.d.ts +15 -6
- package/src/component/_generated/api.js +0 -4
- package/src/component/_generated/dataModel.d.ts +0 -4
- package/src/component/_generated/server.d.ts +0 -4
- package/src/component/_generated/server.js +0 -4
- package/src/component/counter.test.ts +48 -6
- package/src/component/public.ts +86 -2
|
@@ -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({
|
|
@@ -39,4 +42,74 @@ export const count = query({
|
|
|
39
42
|
return counters.reduce((sum, counter) => sum + counter.value, 0);
|
|
40
43
|
},
|
|
41
44
|
});
|
|
45
|
+
export const rebalance = mutation({
|
|
46
|
+
args: { name: v.string(), shards: v.optional(v.number()) },
|
|
47
|
+
handler: async (ctx, args) => {
|
|
48
|
+
const counters = await ctx.db
|
|
49
|
+
.query("counters")
|
|
50
|
+
.withIndex("name", (q) => q.eq("name", args.name))
|
|
51
|
+
.collect();
|
|
52
|
+
const count = counters.reduce((sum, counter) => sum + counter.value, 0);
|
|
53
|
+
const shardCount = args.shards ?? DEFAULT_SHARD_COUNT;
|
|
54
|
+
const value = count / shardCount;
|
|
55
|
+
for (let i = 0; i < shardCount; i++) {
|
|
56
|
+
const shard = counters.find((c) => c.shard === i);
|
|
57
|
+
if (shard) {
|
|
58
|
+
await ctx.db.patch(shard._id, { value });
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
await ctx.db.insert("counters", {
|
|
62
|
+
name: args.name,
|
|
63
|
+
value,
|
|
64
|
+
shard: i,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const toDelete = counters.filter((c) => c.shard >= shardCount);
|
|
69
|
+
for (const counter of toDelete) {
|
|
70
|
+
await ctx.db.delete(counter._id);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
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
|
+
});
|
|
84
|
+
export const estimateCount = query({
|
|
85
|
+
args: {
|
|
86
|
+
name: v.string(),
|
|
87
|
+
readFromShards: v.optional(v.number()),
|
|
88
|
+
shards: v.optional(v.number()),
|
|
89
|
+
},
|
|
90
|
+
handler: async (ctx, args) => {
|
|
91
|
+
const shardCount = args.shards ?? DEFAULT_SHARD_COUNT;
|
|
92
|
+
const readFromShards = Math.min(Math.max(1, args.readFromShards ?? 1), shardCount);
|
|
93
|
+
const shards = shuffle(Array.from({ length: shardCount }, (_, i) => i)).slice(0, readFromShards);
|
|
94
|
+
let readCount = 0;
|
|
95
|
+
for (const shard of shards) {
|
|
96
|
+
const counter = await ctx.db
|
|
97
|
+
.query("counters")
|
|
98
|
+
.withIndex("name", (q) => q.eq("name", args.name).eq("shard", shard))
|
|
99
|
+
.unique();
|
|
100
|
+
if (counter) {
|
|
101
|
+
readCount += counter.value;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return (readCount * shardCount) / readFromShards;
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
// Fisher-Yates shuffle
|
|
108
|
+
function shuffle(array) {
|
|
109
|
+
for (let i = array.length - 1; i > 0; i--) {
|
|
110
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
111
|
+
[array[i], array[j]] = [array[j], array[i]];
|
|
112
|
+
}
|
|
113
|
+
return array;
|
|
114
|
+
}
|
|
42
115
|
//# sourceMappingURL=public.js.map
|
|
@@ -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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"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { Expand, FunctionReference, GenericDataModel, GenericMutationCtx, GenericQueryCtx } from "convex/server";
|
|
1
|
+
import { DocumentByName, Expand, FunctionReference, GenericDataModel, GenericMutationCtx, GenericQueryCtx, TableNamesInDataModel } from "convex/server";
|
|
2
2
|
import { GenericId } from "convex/values";
|
|
3
3
|
import { api } from "../component/_generated/api";
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* A sharded counter is a map from string -> counter, where each counter can
|
|
6
|
+
* be incremented or decremented atomically.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ShardedCounter<ShardsKey extends string> {
|
|
5
9
|
private component;
|
|
6
|
-
private options?;
|
|
7
10
|
/**
|
|
8
11
|
* A sharded counter is a map from string -> counter, where each counter can
|
|
9
12
|
* be incremented or decremented.
|
|
@@ -20,9 +23,11 @@ export declare class ShardedCounter<Shards extends Record<string, number>> {
|
|
|
20
23
|
* keys not in `options.shards`.
|
|
21
24
|
*/
|
|
22
25
|
constructor(component: UseApi<typeof api>, options?: {
|
|
23
|
-
shards?:
|
|
24
|
-
defaultShards?: number
|
|
25
|
-
}
|
|
26
|
+
shards?: Partial<Record<ShardsKey, number>>;
|
|
27
|
+
defaultShards?: number;
|
|
28
|
+
});
|
|
29
|
+
private shardsForKey;
|
|
30
|
+
private stickyShard;
|
|
26
31
|
/**
|
|
27
32
|
* Increase the counter for key `name` by `count`.
|
|
28
33
|
* If `count` is negative, the counter will decrease.
|
|
@@ -30,14 +35,57 @@ export declare class ShardedCounter<Shards extends Record<string, number>> {
|
|
|
30
35
|
* @param name The key to update the counter for.
|
|
31
36
|
* @param count The amount to increment the counter by. Defaults to 1.
|
|
32
37
|
*/
|
|
33
|
-
add<Name extends
|
|
38
|
+
add<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name, count?: number): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Decrease the counter for key `name` by `count`.
|
|
41
|
+
*/
|
|
42
|
+
subtract<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name, count?: number): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Increment the counter for key `name` by 1.
|
|
45
|
+
*/
|
|
46
|
+
inc<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Decrement the counter for key `name` by 1.
|
|
49
|
+
*/
|
|
50
|
+
dec<Name extends ShardsKey>(ctx: RunMutationCtx, name: Name): Promise<void>;
|
|
34
51
|
/**
|
|
35
52
|
* Gets the counter for key `name`.
|
|
36
53
|
*
|
|
37
54
|
* NOTE: this reads from all shards. If used in a mutation, it will contend
|
|
38
55
|
* with all mutations that update the counter for this key.
|
|
39
56
|
*/
|
|
40
|
-
count<Name extends
|
|
57
|
+
count<Name extends ShardsKey>(ctx: RunQueryCtx, name: Name): Promise<number>;
|
|
58
|
+
/**
|
|
59
|
+
* Redistribute counts evenly across the counter's shards.
|
|
60
|
+
*
|
|
61
|
+
* If there were more shards for this counter at some point, those shards
|
|
62
|
+
* will be removed.
|
|
63
|
+
*
|
|
64
|
+
* If there were fewer shards for this counter, or if the random distribution
|
|
65
|
+
* of counts is uneven, the counts will be redistributed evenly.
|
|
66
|
+
*
|
|
67
|
+
* This operation reads and writes all shards, so it can cause contention if
|
|
68
|
+
* called too often.
|
|
69
|
+
*/
|
|
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>;
|
|
77
|
+
/**
|
|
78
|
+
* Estimate the count of a counter by only reading from a subset of shards,
|
|
79
|
+
* and extrapolating the total count.
|
|
80
|
+
*
|
|
81
|
+
* After a `rebalance`, or if there were a lot of data points to yield a
|
|
82
|
+
* random distribution across shards, this should be a good approximation of
|
|
83
|
+
* the total count. If there are few data points, which are not evenly
|
|
84
|
+
* distributed across shards, this will be a poor approximation.
|
|
85
|
+
*
|
|
86
|
+
* Use this to reduce contention when reading the counter.
|
|
87
|
+
*/
|
|
88
|
+
estimateCount<Name extends ShardsKey>(ctx: RunQueryCtx, name: Name, readFromShards?: number): Promise<number>;
|
|
41
89
|
/**
|
|
42
90
|
* Returns an object with methods to update and query the counter for key
|
|
43
91
|
* `name`. For fixed keys, you can call `counter.for("<key>")` to get methods
|
|
@@ -53,23 +101,23 @@ export declare class ShardedCounter<Shards extends Record<string, number>> {
|
|
|
53
101
|
* });
|
|
54
102
|
* ```
|
|
55
103
|
*/
|
|
56
|
-
for<Name extends
|
|
104
|
+
for<Name extends ShardsKey>(name: Name): {
|
|
57
105
|
/**
|
|
58
106
|
* Add `count` to the counter.
|
|
59
107
|
*/
|
|
60
|
-
add: (ctx: RunMutationCtx, count?: number) => Promise<
|
|
108
|
+
add: (ctx: RunMutationCtx, count?: number) => Promise<void>;
|
|
61
109
|
/**
|
|
62
110
|
* Subtract `count` from the counter.
|
|
63
111
|
*/
|
|
64
|
-
subtract: (ctx: RunMutationCtx, count?: number) => Promise<
|
|
112
|
+
subtract: (ctx: RunMutationCtx, count?: number) => Promise<void>;
|
|
65
113
|
/**
|
|
66
114
|
* Increment the counter by 1.
|
|
67
115
|
*/
|
|
68
|
-
inc: (ctx: RunMutationCtx) => Promise<
|
|
116
|
+
inc: (ctx: RunMutationCtx) => Promise<void>;
|
|
69
117
|
/**
|
|
70
118
|
* Decrement the counter by 1.
|
|
71
119
|
*/
|
|
72
|
-
dec: (ctx: RunMutationCtx) => Promise<
|
|
120
|
+
dec: (ctx: RunMutationCtx) => Promise<void>;
|
|
73
121
|
/**
|
|
74
122
|
* Get the current value of the counter.
|
|
75
123
|
*
|
|
@@ -77,8 +125,43 @@ export declare class ShardedCounter<Shards extends Record<string, number>> {
|
|
|
77
125
|
* contend with all mutations that update the counter for this key.
|
|
78
126
|
*/
|
|
79
127
|
count: (ctx: RunQueryCtx) => Promise<number>;
|
|
128
|
+
/**
|
|
129
|
+
* Reset the counter for this key.
|
|
130
|
+
*/
|
|
131
|
+
reset: (ctx: RunMutationCtx) => Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Redistribute counts evenly across the counter's shards.
|
|
134
|
+
*
|
|
135
|
+
* This operation reads and writes all shards, so it can cause contention
|
|
136
|
+
* if called too often.
|
|
137
|
+
*/
|
|
138
|
+
rebalance: (ctx: RunMutationCtx) => Promise<void>;
|
|
139
|
+
/**
|
|
140
|
+
* Estimate the counter by only reading from a subset of shards,
|
|
141
|
+
* and extrapolating the total count.
|
|
142
|
+
*
|
|
143
|
+
* Use this to reduce contention when reading the counter.
|
|
144
|
+
*/
|
|
145
|
+
estimateCount: (ctx: RunQueryCtx, readFromShards?: number) => Promise<number>;
|
|
80
146
|
};
|
|
147
|
+
trigger<Ctx extends RunMutationCtx, Name extends ShardsKey>(name: Name): Trigger<Ctx, GenericDataModel, TableNamesInDataModel<GenericDataModel>>;
|
|
81
148
|
}
|
|
149
|
+
export type Trigger<Ctx, DataModel extends GenericDataModel, TableName extends TableNamesInDataModel<DataModel>> = (ctx: Ctx, change: Change<DataModel, TableName>) => Promise<void>;
|
|
150
|
+
export type Change<DataModel extends GenericDataModel, TableName extends TableNamesInDataModel<DataModel>> = {
|
|
151
|
+
id: GenericId<TableName>;
|
|
152
|
+
} & ({
|
|
153
|
+
operation: "insert";
|
|
154
|
+
oldDoc: null;
|
|
155
|
+
newDoc: DocumentByName<DataModel, TableName>;
|
|
156
|
+
} | {
|
|
157
|
+
operation: "update";
|
|
158
|
+
oldDoc: DocumentByName<DataModel, TableName>;
|
|
159
|
+
newDoc: DocumentByName<DataModel, TableName>;
|
|
160
|
+
} | {
|
|
161
|
+
operation: "delete";
|
|
162
|
+
oldDoc: DocumentByName<DataModel, TableName>;
|
|
163
|
+
newDoc: null;
|
|
164
|
+
});
|
|
82
165
|
type RunQueryCtx = {
|
|
83
166
|
runQuery: GenericQueryCtx<GenericDataModel>["runQuery"];
|
|
84
167
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,
|
|
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
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A sharded counter is a map from string -> counter, where each counter can
|
|
3
|
+
* be incremented or decremented atomically.
|
|
4
|
+
*/
|
|
1
5
|
export class ShardedCounter {
|
|
2
6
|
component;
|
|
3
|
-
options;
|
|
4
7
|
/**
|
|
5
8
|
* A sharded counter is a map from string -> counter, where each counter can
|
|
6
9
|
* be incremented or decremented.
|
|
@@ -18,8 +21,17 @@ export class ShardedCounter {
|
|
|
18
21
|
*/
|
|
19
22
|
constructor(component, options) {
|
|
20
23
|
this.component = component;
|
|
21
|
-
this.
|
|
24
|
+
this.stickyShard = {};
|
|
25
|
+
const defaultShards = options?.defaultShards;
|
|
26
|
+
this.shardsForKey = (name) => {
|
|
27
|
+
const explicitShards = options?.shards?.[name];
|
|
28
|
+
return explicitShards ?? defaultShards;
|
|
29
|
+
};
|
|
22
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;
|
|
23
35
|
/**
|
|
24
36
|
* Increase the counter for key `name` by `count`.
|
|
25
37
|
* If `count` is negative, the counter will decrease.
|
|
@@ -28,12 +40,31 @@ export class ShardedCounter {
|
|
|
28
40
|
* @param count The amount to increment the counter by. Defaults to 1.
|
|
29
41
|
*/
|
|
30
42
|
async add(ctx, name, count = 1) {
|
|
31
|
-
const
|
|
32
|
-
return ctx.runMutation(this.component.public.add, {
|
|
43
|
+
const shard = await ctx.runMutation(this.component.public.add, {
|
|
33
44
|
name,
|
|
34
45
|
count,
|
|
35
|
-
|
|
46
|
+
shard: this.stickyShard?.[name],
|
|
47
|
+
shards: this.shardsForKey(name),
|
|
36
48
|
});
|
|
49
|
+
this.stickyShard[name] = shard;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Decrease the counter for key `name` by `count`.
|
|
53
|
+
*/
|
|
54
|
+
async subtract(ctx, name, count = 1) {
|
|
55
|
+
return this.add(ctx, name, -count);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Increment the counter for key `name` by 1.
|
|
59
|
+
*/
|
|
60
|
+
async inc(ctx, name) {
|
|
61
|
+
return this.add(ctx, name, 1);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Decrement the counter for key `name` by 1.
|
|
65
|
+
*/
|
|
66
|
+
async dec(ctx, name) {
|
|
67
|
+
return this.add(ctx, name, -1);
|
|
37
68
|
}
|
|
38
69
|
/**
|
|
39
70
|
* Gets the counter for key `name`.
|
|
@@ -44,6 +75,50 @@ export class ShardedCounter {
|
|
|
44
75
|
async count(ctx, name) {
|
|
45
76
|
return ctx.runQuery(this.component.public.count, { name });
|
|
46
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Redistribute counts evenly across the counter's shards.
|
|
80
|
+
*
|
|
81
|
+
* If there were more shards for this counter at some point, those shards
|
|
82
|
+
* will be removed.
|
|
83
|
+
*
|
|
84
|
+
* If there were fewer shards for this counter, or if the random distribution
|
|
85
|
+
* of counts is uneven, the counts will be redistributed evenly.
|
|
86
|
+
*
|
|
87
|
+
* This operation reads and writes all shards, so it can cause contention if
|
|
88
|
+
* called too often.
|
|
89
|
+
*/
|
|
90
|
+
async rebalance(ctx, name) {
|
|
91
|
+
await ctx.runMutation(this.component.public.rebalance, {
|
|
92
|
+
name,
|
|
93
|
+
shards: this.shardsForKey(name),
|
|
94
|
+
});
|
|
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
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Estimate the count of a counter by only reading from a subset of shards,
|
|
106
|
+
* and extrapolating the total count.
|
|
107
|
+
*
|
|
108
|
+
* After a `rebalance`, or if there were a lot of data points to yield a
|
|
109
|
+
* random distribution across shards, this should be a good approximation of
|
|
110
|
+
* the total count. If there are few data points, which are not evenly
|
|
111
|
+
* distributed across shards, this will be a poor approximation.
|
|
112
|
+
*
|
|
113
|
+
* Use this to reduce contention when reading the counter.
|
|
114
|
+
*/
|
|
115
|
+
async estimateCount(ctx, name, readFromShards = 1) {
|
|
116
|
+
return await ctx.runQuery(this.component.public.estimateCount, {
|
|
117
|
+
name,
|
|
118
|
+
shards: this.shardsForKey(name),
|
|
119
|
+
readFromShards,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
47
122
|
/**
|
|
48
123
|
* Returns an object with methods to update and query the counter for key
|
|
49
124
|
* `name`. For fixed keys, you can call `counter.for("<key>")` to get methods
|
|
@@ -84,6 +159,34 @@ export class ShardedCounter {
|
|
|
84
159
|
* contend with all mutations that update the counter for this key.
|
|
85
160
|
*/
|
|
86
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),
|
|
166
|
+
/**
|
|
167
|
+
* Redistribute counts evenly across the counter's shards.
|
|
168
|
+
*
|
|
169
|
+
* This operation reads and writes all shards, so it can cause contention
|
|
170
|
+
* if called too often.
|
|
171
|
+
*/
|
|
172
|
+
rebalance: async (ctx) => this.rebalance(ctx, name),
|
|
173
|
+
/**
|
|
174
|
+
* Estimate the counter by only reading from a subset of shards,
|
|
175
|
+
* and extrapolating the total count.
|
|
176
|
+
*
|
|
177
|
+
* Use this to reduce contention when reading the counter.
|
|
178
|
+
*/
|
|
179
|
+
estimateCount: async (ctx, readFromShards = 1) => this.estimateCount(ctx, name, readFromShards),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
trigger(name) {
|
|
183
|
+
return async (ctx, change) => {
|
|
184
|
+
if (change.operation === "insert") {
|
|
185
|
+
await this.inc(ctx, name);
|
|
186
|
+
}
|
|
187
|
+
else if (change.operation === "delete") {
|
|
188
|
+
await this.dec(ctx, name);
|
|
189
|
+
}
|
|
87
190
|
};
|
|
88
191
|
}
|
|
89
192
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/component/_generated/api.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/component/_generated/api.js"],"names":[],"mappings":"AAYA;;;;;;;GAOG;AACH,iDAA0B;AAC1B,sDAA+B;AAC/B;;EAA8C"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* prettier-ignore-start */
|
|
2
1
|
/* eslint-disable */
|
|
3
2
|
/**
|
|
4
3
|
* Generated `api` utility.
|
|
@@ -20,5 +19,4 @@ import { anyApi, componentsGeneric } from "convex/server";
|
|
|
20
19
|
export const api = anyApi;
|
|
21
20
|
export const internal = anyApi;
|
|
22
21
|
export const components = componentsGeneric();
|
|
23
|
-
/* prettier-ignore-end */
|
|
24
22
|
//# sourceMappingURL=api.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../../src/component/_generated/api.js"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../../src/component/_generated/api.js"],"names":[],"mappings":"AAAA,oBAAoB;AACpB;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC;AAC1B,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC;AAC/B,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../src/component/_generated/server.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../src/component/_generated/server.js"],"names":[],"mappings":"AAqBA;;;;;;;GAOG;AACH,wEAAkC;AAElC;;;;;;;GAOG;AACH,kFAAkD;AAElD;;;;;;;GAOG;AACH,8EAAwC;AAExC;;;;;;;GAOG;AACH,wFAAwD;AAExD;;;;;;;;;;GAUG;AACH,0EAAoC;AAEpC;;;;;GAKG;AACH,oFAAoD;AAEpD;;;;;;GAMG;AACH,8MAA4C"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* prettier-ignore-start */
|
|
2
1
|
/* eslint-disable */
|
|
3
2
|
/**
|
|
4
3
|
* Generated utilities for implementing server-side Convex query and mutation functions.
|
|
@@ -72,5 +71,4 @@ export const internalAction = internalActionGeneric;
|
|
|
72
71
|
* @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
|
|
73
72
|
*/
|
|
74
73
|
export const httpAction = httpActionGeneric;
|
|
75
|
-
/* prettier-ignore-end */
|
|
76
74
|
//# sourceMappingURL=server.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../src/component/_generated/server.js"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../src/component/_generated/server.js"],"names":[],"mappings":"AAAA,oBAAoB;AACpB;;;;;;;GAOG;AAEH,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAEvB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,YAAY,CAAC;AAElC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,eAAe,CAAC;AAExC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAExD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,aAAa,CAAC;AAEpC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,qBAAqB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,CAAC"}
|
|
@@ -1,10 +1,23 @@
|
|
|
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
|
+
export declare const rebalance: import("convex/server").RegisteredMutation<"public", {
|
|
12
|
+
shards?: number | undefined;
|
|
13
|
+
name: string;
|
|
14
|
+
}, Promise<void>>;
|
|
15
|
+
export declare const reset: import("convex/server").RegisteredMutation<"public", {
|
|
16
|
+
name: string;
|
|
17
|
+
}, Promise<void>>;
|
|
18
|
+
export declare const estimateCount: import("convex/server").RegisteredQuery<"public", {
|
|
19
|
+
shards?: number | undefined;
|
|
20
|
+
readFromShards?: number | undefined;
|
|
21
|
+
name: string;
|
|
22
|
+
}, Promise<number>>;
|
|
10
23
|
//# sourceMappingURL=public.d.ts.map
|
|
@@ -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({
|
|
@@ -39,4 +42,74 @@ export const count = query({
|
|
|
39
42
|
return counters.reduce((sum, counter) => sum + counter.value, 0);
|
|
40
43
|
},
|
|
41
44
|
});
|
|
45
|
+
export const rebalance = mutation({
|
|
46
|
+
args: { name: v.string(), shards: v.optional(v.number()) },
|
|
47
|
+
handler: async (ctx, args) => {
|
|
48
|
+
const counters = await ctx.db
|
|
49
|
+
.query("counters")
|
|
50
|
+
.withIndex("name", (q) => q.eq("name", args.name))
|
|
51
|
+
.collect();
|
|
52
|
+
const count = counters.reduce((sum, counter) => sum + counter.value, 0);
|
|
53
|
+
const shardCount = args.shards ?? DEFAULT_SHARD_COUNT;
|
|
54
|
+
const value = count / shardCount;
|
|
55
|
+
for (let i = 0; i < shardCount; i++) {
|
|
56
|
+
const shard = counters.find((c) => c.shard === i);
|
|
57
|
+
if (shard) {
|
|
58
|
+
await ctx.db.patch(shard._id, { value });
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
await ctx.db.insert("counters", {
|
|
62
|
+
name: args.name,
|
|
63
|
+
value,
|
|
64
|
+
shard: i,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const toDelete = counters.filter((c) => c.shard >= shardCount);
|
|
69
|
+
for (const counter of toDelete) {
|
|
70
|
+
await ctx.db.delete(counter._id);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
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
|
+
});
|
|
84
|
+
export const estimateCount = query({
|
|
85
|
+
args: {
|
|
86
|
+
name: v.string(),
|
|
87
|
+
readFromShards: v.optional(v.number()),
|
|
88
|
+
shards: v.optional(v.number()),
|
|
89
|
+
},
|
|
90
|
+
handler: async (ctx, args) => {
|
|
91
|
+
const shardCount = args.shards ?? DEFAULT_SHARD_COUNT;
|
|
92
|
+
const readFromShards = Math.min(Math.max(1, args.readFromShards ?? 1), shardCount);
|
|
93
|
+
const shards = shuffle(Array.from({ length: shardCount }, (_, i) => i)).slice(0, readFromShards);
|
|
94
|
+
let readCount = 0;
|
|
95
|
+
for (const shard of shards) {
|
|
96
|
+
const counter = await ctx.db
|
|
97
|
+
.query("counters")
|
|
98
|
+
.withIndex("name", (q) => q.eq("name", args.name).eq("shard", shard))
|
|
99
|
+
.unique();
|
|
100
|
+
if (counter) {
|
|
101
|
+
readCount += counter.value;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return (readCount * shardCount) / readFromShards;
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
// Fisher-Yates shuffle
|
|
108
|
+
function shuffle(array) {
|
|
109
|
+
for (let i = array.length - 1; i > 0; i--) {
|
|
110
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
111
|
+
[array[i], array[j]] = [array[j], array[i]];
|
|
112
|
+
}
|
|
113
|
+
return array;
|
|
114
|
+
}
|
|
42
115
|
//# sourceMappingURL=public.js.map
|
|
@@ -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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"}
|