@dxos/timeframe 0.1.57-main.e87098f → 0.1.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/index.mjs +23 -18
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +23 -18
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/bench.test.d.ts +2 -0
- package/dist/types/src/bench.test.d.ts.map +1 -0
- package/dist/types/src/timeframe.d.ts +1 -1
- package/dist/types/src/timeframe.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/bench.test.ts +107 -0
- package/src/timeframe.ts +23 -22
|
@@ -3,11 +3,9 @@ import "@dxos/node-std/globals";
|
|
|
3
3
|
// packages/common/timeframe/src/timeframe.ts
|
|
4
4
|
import { inspect } from "@dxos/node-std/util";
|
|
5
5
|
import { equalsSymbol } from "@dxos/debug";
|
|
6
|
-
import { PublicKey } from "@dxos/keys";
|
|
7
|
-
import { ComplexMap } from "@dxos/util";
|
|
8
6
|
var Timeframe = class _Timeframe {
|
|
9
7
|
constructor(frames = []) {
|
|
10
|
-
this._frames = new
|
|
8
|
+
this._frames = /* @__PURE__ */ new Map();
|
|
11
9
|
for (const [key, seq] of frames) {
|
|
12
10
|
this.set(key, seq);
|
|
13
11
|
}
|
|
@@ -26,15 +24,22 @@ var Timeframe = class _Timeframe {
|
|
|
26
24
|
}
|
|
27
25
|
// TODO(burdon): Rename getFrame.
|
|
28
26
|
get(key) {
|
|
29
|
-
return this._frames.get(key);
|
|
27
|
+
return this._frames.get(key.toHex())?.seq;
|
|
30
28
|
}
|
|
31
29
|
// TODO(burdon): Rename setFrame.
|
|
32
|
-
set(key,
|
|
33
|
-
|
|
30
|
+
set(key, seq) {
|
|
31
|
+
const hex = key.toHex();
|
|
32
|
+
this._frames.set(hex, {
|
|
33
|
+
key,
|
|
34
|
+
seq
|
|
35
|
+
});
|
|
34
36
|
}
|
|
35
37
|
// TODO(burdon): Change to getter.
|
|
36
38
|
frames() {
|
|
37
|
-
return Array.from(this._frames.
|
|
39
|
+
return Array.from(this._frames.values()).map(({ key, seq }) => [
|
|
40
|
+
key,
|
|
41
|
+
seq
|
|
42
|
+
]);
|
|
38
43
|
}
|
|
39
44
|
// TODO(burdon): Change to getter.
|
|
40
45
|
size() {
|
|
@@ -49,7 +54,7 @@ var Timeframe = class _Timeframe {
|
|
|
49
54
|
* @param keys
|
|
50
55
|
*/
|
|
51
56
|
withoutKeys(keys) {
|
|
52
|
-
return new _Timeframe(this.frames().filter(([frameKey]) => keys.every((key) =>
|
|
57
|
+
return new _Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => !key.equals(frameKey))));
|
|
53
58
|
}
|
|
54
59
|
map(fn) {
|
|
55
60
|
return new _Timeframe(this.frames().map(fn));
|
|
@@ -58,13 +63,13 @@ var Timeframe = class _Timeframe {
|
|
|
58
63
|
* Returns a total amount of messages represented by this timeframe.
|
|
59
64
|
*/
|
|
60
65
|
totalMessages() {
|
|
61
|
-
return Array.from(this._frames.values()).reduce((result, seq) => result + seq + 1, 0);
|
|
66
|
+
return Array.from(this._frames.values()).reduce((result, { seq }) => result + seq + 1, 0);
|
|
62
67
|
}
|
|
63
68
|
/**
|
|
64
69
|
* Returns a total amount of messages that are present in this timeframe but are missing in `base`.
|
|
65
70
|
*/
|
|
66
71
|
newMessages(base) {
|
|
67
|
-
return Array.from(this._frames.entries()).reduce((result, [
|
|
72
|
+
return Array.from(this._frames.entries()).reduce((result, [hex, { seq }]) => result + Math.max(seq - (base._frames.get(hex)?.seq ?? -1), 0), 0);
|
|
68
73
|
}
|
|
69
74
|
/**
|
|
70
75
|
* Used by NodeJS to get textual representation of this object in `console.log`.
|
|
@@ -85,10 +90,10 @@ var Timeframe = class _Timeframe {
|
|
|
85
90
|
static merge(...timeframes) {
|
|
86
91
|
const result = new _Timeframe();
|
|
87
92
|
for (const timeframe of timeframes) {
|
|
88
|
-
for (const [
|
|
89
|
-
const
|
|
90
|
-
if (
|
|
91
|
-
result.set(
|
|
93
|
+
for (const [hex, entry] of timeframe._frames) {
|
|
94
|
+
const currentEntry = result._frames.get(hex);
|
|
95
|
+
if (currentEntry === void 0 || entry.seq > currentEntry.seq) {
|
|
96
|
+
result._frames.set(hex, entry);
|
|
92
97
|
}
|
|
93
98
|
}
|
|
94
99
|
}
|
|
@@ -100,10 +105,10 @@ var Timeframe = class _Timeframe {
|
|
|
100
105
|
*/
|
|
101
106
|
static dependencies(tf1, tf2) {
|
|
102
107
|
const result = new _Timeframe();
|
|
103
|
-
for (const [
|
|
104
|
-
const
|
|
105
|
-
if (
|
|
106
|
-
result.set(
|
|
108
|
+
for (const [hex, entry] of tf1._frames) {
|
|
109
|
+
const otherEntry = tf2._frames.get(hex);
|
|
110
|
+
if (otherEntry === void 0 || otherEntry.seq < entry.seq) {
|
|
111
|
+
result._frames.set(hex, entry);
|
|
107
112
|
}
|
|
108
113
|
}
|
|
109
114
|
return result;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/timeframe.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2020 DXOS.org\n//\n\nimport { inspect } from 'node:util';\n\nimport { equalsSymbol, Equatable } from '@dxos/debug';\nimport { PublicKey } from '@dxos/keys';\
|
|
5
|
-
"mappings": ";;;AAIA,SAASA,eAAe;AAExB,SAASC,oBAA+B;
|
|
6
|
-
"names": ["inspect", "equalsSymbol", "
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2020 DXOS.org\n//\n\nimport { inspect } from 'node:util';\n\nimport { equalsSymbol, Equatable } from '@dxos/debug';\nimport { PublicKey } from '@dxos/keys';\n\ntype Entry = {\n key: PublicKey;\n seq: number;\n};\n\n/**\n * A vector clock that implements ordering over a set of feed messages.\n */\nexport class Timeframe implements Equatable {\n private readonly _frames = new Map<string, Entry>();\n\n constructor(frames: [PublicKey, number][] = []) {\n for (const [key, seq] of frames) {\n this.set(key, seq);\n }\n }\n\n toJSON() {\n return this.frames().reduce((frames: Record<string, number>, [key, seq]) => {\n frames[key.truncate()] = seq;\n return frames;\n }, {});\n }\n\n toString() {\n return `(${this.frames()\n .map(([key, seq]) => `${key.truncate()}[${seq}]`)\n .join(', ')})`;\n }\n\n equals(object: Timeframe) {\n return this.size() === object.size() && this.frames().every(([key, seq]) => object.get(key) === seq);\n }\n\n // TODO(burdon): Rename getFrame.\n get(key: PublicKey): number | undefined {\n return this._frames.get(key.toHex())?.seq;\n }\n\n // TODO(burdon): Rename setFrame.\n set(key: PublicKey, seq: number) {\n const hex = key.toHex();\n this._frames.set(hex, { key, seq });\n }\n\n // TODO(burdon): Change to getter.\n frames(): [PublicKey, number][] {\n return Array.from(this._frames.values()).map(({ key, seq }) => [key, seq]);\n }\n\n // TODO(burdon): Change to getter.\n size() {\n return this._frames.size;\n }\n\n // TODO(burdon): Change to getter (empty).\n isEmpty() {\n return this.size() === 0;\n }\n\n /**\n * Returns a new timeframe with specified keys removed.\n * @param keys\n */\n withoutKeys(keys: PublicKey[]): Timeframe {\n return new Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => !key.equals(frameKey))));\n }\n\n map(fn: (frame: [key: PublicKey, seq: number]) => [PublicKey, number]): Timeframe {\n return new Timeframe(this.frames().map(fn));\n }\n\n /**\n * Returns a total amount of messages represented by this timeframe.\n */\n totalMessages(): number {\n return Array.from(this._frames.values()).reduce((result, { seq }) => result + seq + 1, 0);\n }\n\n /**\n * Returns a total amount of messages that are present in this timeframe but are missing in `base`.\n */\n newMessages(base: Timeframe) {\n return Array.from(this._frames.entries()).reduce(\n (result, [hex, { seq }]) => result + Math.max(seq - (base._frames.get(hex)?.seq ?? -1), 0),\n 0,\n );\n }\n\n /**\n * Used by NodeJS to get textual representation of this object in `console.log`.\n */\n [inspect.custom]() {\n return `Timeframe${this.toString()}`;\n }\n\n [equalsSymbol](other: any) {\n if (!(other instanceof Timeframe)) {\n return false;\n }\n\n return this.equals(other);\n }\n\n /**\n * Merges the values, updating the highest sequence numbers.\n * @param timeframes\n */\n static merge(...timeframes: Timeframe[]): Timeframe {\n const result = new Timeframe();\n for (const timeframe of timeframes) {\n for (const [hex, entry] of timeframe._frames) {\n const currentEntry = result._frames.get(hex);\n if (currentEntry === undefined || entry.seq > currentEntry.seq) {\n result._frames.set(hex, entry);\n }\n }\n }\n\n return result;\n }\n\n /**\n * Compares two timeframes and returns an array of frames from the first timeframe where the sequence number\n * is greater than the associated sequence number from the second timeframe.\n */\n static dependencies(tf1: Timeframe, tf2: Timeframe): Timeframe {\n const result = new Timeframe();\n for (const [hex, entry] of tf1._frames) {\n const otherEntry = tf2._frames.get(hex);\n if (otherEntry === undefined || otherEntry.seq < entry.seq) {\n result._frames.set(hex, entry);\n }\n }\n\n return result;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["inspect", "equalsSymbol", "Timeframe", "constructor", "frames", "_frames", "Map", "key", "seq", "set", "toJSON", "reduce", "truncate", "toString", "map", "join", "equals", "object", "size", "every", "get", "toHex", "hex", "Array", "from", "values", "isEmpty", "withoutKeys", "keys", "filter", "frameKey", "fn", "totalMessages", "result", "newMessages", "base", "entries", "Math", "max", "inspect", "custom", "equalsSymbol", "other", "merge", "timeframes", "timeframe", "entry", "currentEntry", "undefined", "dependencies", "tf1", "tf2", "otherEntry"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/common/timeframe/src/timeframe.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/common/timeframe/src/timeframe.ts":{"bytes":13703,"imports":[{"path":"@dxos/node-std/util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true}],"format":"esm"},"packages/common/timeframe/src/index.ts":{"bytes":460,"imports":[{"path":"packages/common/timeframe/src/timeframe.ts","kind":"import-statement","original":"./timeframe"}],"format":"esm"}},"outputs":{"packages/common/timeframe/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7066},"packages/common/timeframe/dist/lib/browser/index.mjs":{"imports":[{"path":"@dxos/node-std/util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true}],"exports":["Timeframe"],"entryPoint":"packages/common/timeframe/src/index.ts","inputs":{"packages/common/timeframe/src/timeframe.ts":{"bytesInOutput":3277},"packages/common/timeframe/src/index.ts":{"bytesInOutput":0}},"bytes":3416}}}
|
package/dist/lib/node/index.cjs
CHANGED
|
@@ -27,11 +27,9 @@ module.exports = __toCommonJS(src_exports);
|
|
|
27
27
|
// packages/common/timeframe/src/timeframe.ts
|
|
28
28
|
var import_node_util = require("node:util");
|
|
29
29
|
var import_debug = require("@dxos/debug");
|
|
30
|
-
var import_keys = require("@dxos/keys");
|
|
31
|
-
var import_util = require("@dxos/util");
|
|
32
30
|
var Timeframe = class _Timeframe {
|
|
33
31
|
constructor(frames = []) {
|
|
34
|
-
this._frames = new
|
|
32
|
+
this._frames = /* @__PURE__ */ new Map();
|
|
35
33
|
for (const [key, seq] of frames) {
|
|
36
34
|
this.set(key, seq);
|
|
37
35
|
}
|
|
@@ -50,15 +48,22 @@ var Timeframe = class _Timeframe {
|
|
|
50
48
|
}
|
|
51
49
|
// TODO(burdon): Rename getFrame.
|
|
52
50
|
get(key) {
|
|
53
|
-
return this._frames.get(key);
|
|
51
|
+
return this._frames.get(key.toHex())?.seq;
|
|
54
52
|
}
|
|
55
53
|
// TODO(burdon): Rename setFrame.
|
|
56
|
-
set(key,
|
|
57
|
-
|
|
54
|
+
set(key, seq) {
|
|
55
|
+
const hex = key.toHex();
|
|
56
|
+
this._frames.set(hex, {
|
|
57
|
+
key,
|
|
58
|
+
seq
|
|
59
|
+
});
|
|
58
60
|
}
|
|
59
61
|
// TODO(burdon): Change to getter.
|
|
60
62
|
frames() {
|
|
61
|
-
return Array.from(this._frames.
|
|
63
|
+
return Array.from(this._frames.values()).map(({ key, seq }) => [
|
|
64
|
+
key,
|
|
65
|
+
seq
|
|
66
|
+
]);
|
|
62
67
|
}
|
|
63
68
|
// TODO(burdon): Change to getter.
|
|
64
69
|
size() {
|
|
@@ -73,7 +78,7 @@ var Timeframe = class _Timeframe {
|
|
|
73
78
|
* @param keys
|
|
74
79
|
*/
|
|
75
80
|
withoutKeys(keys) {
|
|
76
|
-
return new _Timeframe(this.frames().filter(([frameKey]) => keys.every((key) =>
|
|
81
|
+
return new _Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => !key.equals(frameKey))));
|
|
77
82
|
}
|
|
78
83
|
map(fn) {
|
|
79
84
|
return new _Timeframe(this.frames().map(fn));
|
|
@@ -82,13 +87,13 @@ var Timeframe = class _Timeframe {
|
|
|
82
87
|
* Returns a total amount of messages represented by this timeframe.
|
|
83
88
|
*/
|
|
84
89
|
totalMessages() {
|
|
85
|
-
return Array.from(this._frames.values()).reduce((result, seq) => result + seq + 1, 0);
|
|
90
|
+
return Array.from(this._frames.values()).reduce((result, { seq }) => result + seq + 1, 0);
|
|
86
91
|
}
|
|
87
92
|
/**
|
|
88
93
|
* Returns a total amount of messages that are present in this timeframe but are missing in `base`.
|
|
89
94
|
*/
|
|
90
95
|
newMessages(base) {
|
|
91
|
-
return Array.from(this._frames.entries()).reduce((result, [
|
|
96
|
+
return Array.from(this._frames.entries()).reduce((result, [hex, { seq }]) => result + Math.max(seq - (base._frames.get(hex)?.seq ?? -1), 0), 0);
|
|
92
97
|
}
|
|
93
98
|
/**
|
|
94
99
|
* Used by NodeJS to get textual representation of this object in `console.log`.
|
|
@@ -109,10 +114,10 @@ var Timeframe = class _Timeframe {
|
|
|
109
114
|
static merge(...timeframes) {
|
|
110
115
|
const result = new _Timeframe();
|
|
111
116
|
for (const timeframe of timeframes) {
|
|
112
|
-
for (const [
|
|
113
|
-
const
|
|
114
|
-
if (
|
|
115
|
-
result.set(
|
|
117
|
+
for (const [hex, entry] of timeframe._frames) {
|
|
118
|
+
const currentEntry = result._frames.get(hex);
|
|
119
|
+
if (currentEntry === void 0 || entry.seq > currentEntry.seq) {
|
|
120
|
+
result._frames.set(hex, entry);
|
|
116
121
|
}
|
|
117
122
|
}
|
|
118
123
|
}
|
|
@@ -124,10 +129,10 @@ var Timeframe = class _Timeframe {
|
|
|
124
129
|
*/
|
|
125
130
|
static dependencies(tf1, tf2) {
|
|
126
131
|
const result = new _Timeframe();
|
|
127
|
-
for (const [
|
|
128
|
-
const
|
|
129
|
-
if (
|
|
130
|
-
result.set(
|
|
132
|
+
for (const [hex, entry] of tf1._frames) {
|
|
133
|
+
const otherEntry = tf2._frames.get(hex);
|
|
134
|
+
if (otherEntry === void 0 || otherEntry.seq < entry.seq) {
|
|
135
|
+
result._frames.set(hex, entry);
|
|
131
136
|
}
|
|
132
137
|
}
|
|
133
138
|
return result;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/index.ts", "../../../src/timeframe.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2021 DXOS.org\n//\n\nexport * from './timeframe';\n", "//\n// Copyright 2020 DXOS.org\n//\n\nimport { inspect } from 'node:util';\n\nimport { equalsSymbol, Equatable } from '@dxos/debug';\nimport { PublicKey } from '@dxos/keys';\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;ACIA,uBAAwB;AAExB,mBAAwC;
|
|
6
|
-
"names": ["Timeframe", "constructor", "frames", "_frames", "
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2021 DXOS.org\n//\n\nexport * from './timeframe';\n", "//\n// Copyright 2020 DXOS.org\n//\n\nimport { inspect } from 'node:util';\n\nimport { equalsSymbol, Equatable } from '@dxos/debug';\nimport { PublicKey } from '@dxos/keys';\n\ntype Entry = {\n key: PublicKey;\n seq: number;\n};\n\n/**\n * A vector clock that implements ordering over a set of feed messages.\n */\nexport class Timeframe implements Equatable {\n private readonly _frames = new Map<string, Entry>();\n\n constructor(frames: [PublicKey, number][] = []) {\n for (const [key, seq] of frames) {\n this.set(key, seq);\n }\n }\n\n toJSON() {\n return this.frames().reduce((frames: Record<string, number>, [key, seq]) => {\n frames[key.truncate()] = seq;\n return frames;\n }, {});\n }\n\n toString() {\n return `(${this.frames()\n .map(([key, seq]) => `${key.truncate()}[${seq}]`)\n .join(', ')})`;\n }\n\n equals(object: Timeframe) {\n return this.size() === object.size() && this.frames().every(([key, seq]) => object.get(key) === seq);\n }\n\n // TODO(burdon): Rename getFrame.\n get(key: PublicKey): number | undefined {\n return this._frames.get(key.toHex())?.seq;\n }\n\n // TODO(burdon): Rename setFrame.\n set(key: PublicKey, seq: number) {\n const hex = key.toHex();\n this._frames.set(hex, { key, seq });\n }\n\n // TODO(burdon): Change to getter.\n frames(): [PublicKey, number][] {\n return Array.from(this._frames.values()).map(({ key, seq }) => [key, seq]);\n }\n\n // TODO(burdon): Change to getter.\n size() {\n return this._frames.size;\n }\n\n // TODO(burdon): Change to getter (empty).\n isEmpty() {\n return this.size() === 0;\n }\n\n /**\n * Returns a new timeframe with specified keys removed.\n * @param keys\n */\n withoutKeys(keys: PublicKey[]): Timeframe {\n return new Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => !key.equals(frameKey))));\n }\n\n map(fn: (frame: [key: PublicKey, seq: number]) => [PublicKey, number]): Timeframe {\n return new Timeframe(this.frames().map(fn));\n }\n\n /**\n * Returns a total amount of messages represented by this timeframe.\n */\n totalMessages(): number {\n return Array.from(this._frames.values()).reduce((result, { seq }) => result + seq + 1, 0);\n }\n\n /**\n * Returns a total amount of messages that are present in this timeframe but are missing in `base`.\n */\n newMessages(base: Timeframe) {\n return Array.from(this._frames.entries()).reduce(\n (result, [hex, { seq }]) => result + Math.max(seq - (base._frames.get(hex)?.seq ?? -1), 0),\n 0,\n );\n }\n\n /**\n * Used by NodeJS to get textual representation of this object in `console.log`.\n */\n [inspect.custom]() {\n return `Timeframe${this.toString()}`;\n }\n\n [equalsSymbol](other: any) {\n if (!(other instanceof Timeframe)) {\n return false;\n }\n\n return this.equals(other);\n }\n\n /**\n * Merges the values, updating the highest sequence numbers.\n * @param timeframes\n */\n static merge(...timeframes: Timeframe[]): Timeframe {\n const result = new Timeframe();\n for (const timeframe of timeframes) {\n for (const [hex, entry] of timeframe._frames) {\n const currentEntry = result._frames.get(hex);\n if (currentEntry === undefined || entry.seq > currentEntry.seq) {\n result._frames.set(hex, entry);\n }\n }\n }\n\n return result;\n }\n\n /**\n * Compares two timeframes and returns an array of frames from the first timeframe where the sequence number\n * is greater than the associated sequence number from the second timeframe.\n */\n static dependencies(tf1: Timeframe, tf2: Timeframe): Timeframe {\n const result = new Timeframe();\n for (const [hex, entry] of tf1._frames) {\n const otherEntry = tf2._frames.get(hex);\n if (otherEntry === undefined || otherEntry.seq < entry.seq) {\n result._frames.set(hex, entry);\n }\n }\n\n return result;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Timeframe", "constructor", "frames", "_frames", "Map", "key", "seq", "set", "toJSON", "reduce", "truncate", "toString", "map", "join", "equals", "object", "size", "every", "get", "toHex", "hex", "Array", "from", "values", "isEmpty", "withoutKeys", "keys", "filter", "frameKey", "fn", "totalMessages", "result", "newMessages", "base", "entries", "Math", "max", "inspect", "custom", "equalsSymbol", "other", "merge", "timeframes", "timeframe", "entry", "currentEntry", "undefined", "dependencies", "tf1", "tf2", "otherEntry"]
|
|
7
7
|
}
|
package/dist/lib/node/meta.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/common/timeframe/src/timeframe.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/common/timeframe/src/timeframe.ts":{"bytes":13703,"imports":[{"path":"node:util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true}],"format":"esm"},"packages/common/timeframe/src/index.ts":{"bytes":460,"imports":[{"path":"packages/common/timeframe/src/timeframe.ts","kind":"import-statement","original":"./timeframe"}],"format":"esm"}},"outputs":{"packages/common/timeframe/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7156},"packages/common/timeframe/dist/lib/node/index.cjs":{"imports":[{"path":"node:util","kind":"require-call","external":true},{"path":"@dxos/debug","kind":"require-call","external":true}],"exports":[],"entryPoint":"packages/common/timeframe/src/index.ts","inputs":{"packages/common/timeframe/src/index.ts":{"bytesInOutput":123},"packages/common/timeframe/src/timeframe.ts":{"bytesInOutput":3304}},"bytes":4454}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bench.test.d.ts","sourceRoot":"","sources":["../../../src/bench.test.ts"],"names":[],"mappings":""}
|
|
@@ -12,7 +12,7 @@ export declare class Timeframe implements Equatable {
|
|
|
12
12
|
toString(): string;
|
|
13
13
|
equals(object: Timeframe): boolean;
|
|
14
14
|
get(key: PublicKey): number | undefined;
|
|
15
|
-
set(key: PublicKey,
|
|
15
|
+
set(key: PublicKey, seq: number): void;
|
|
16
16
|
frames(): [PublicKey, number][];
|
|
17
17
|
size(): number;
|
|
18
18
|
isEmpty(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeframe.d.ts","sourceRoot":"","sources":["../../../src/timeframe.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"timeframe.d.ts","sourceRoot":"","sources":["../../../src/timeframe.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAOvC;;GAEG;AACH,qBAAa,SAAU,YAAW,SAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;gBAExC,MAAM,GAAE,CAAC,SAAS,EAAE,MAAM,CAAC,EAAO;IAM9C,MAAM;IAON,QAAQ;IAMR,MAAM,CAAC,MAAM,EAAE,SAAS;IAKxB,GAAG,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS;IAKvC,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM;IAM/B,MAAM,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE;IAK/B,IAAI;IAKJ,OAAO;IAIP;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,SAAS;IAIzC,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,SAAS;IAIjF;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,SAAS;IAO3B;;OAEG;IACH,CAAC,OAAO,CAAC,MAAM,CAAC;IAIhB,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE,GAAG;IAQzB;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,GAAG,UAAU,EAAE,SAAS,EAAE,GAAG,SAAS;IAcnD;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,SAAS;CAW/D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/timeframe",
|
|
3
|
-
"version": "0.1.57
|
|
3
|
+
"version": "0.1.57",
|
|
4
4
|
"description": "Timeframe vector clock.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
"src"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@dxos/debug": "0.1.57
|
|
20
|
-
"@dxos/keys": "0.1.57
|
|
21
|
-
"@dxos/log": "0.1.57
|
|
22
|
-
"@dxos/node-std": "0.1.57
|
|
23
|
-
"@dxos/util": "0.1.57
|
|
19
|
+
"@dxos/debug": "0.1.57",
|
|
20
|
+
"@dxos/keys": "0.1.57",
|
|
21
|
+
"@dxos/log": "0.1.57",
|
|
22
|
+
"@dxos/node-std": "0.1.57",
|
|
23
|
+
"@dxos/util": "0.1.57"
|
|
24
24
|
},
|
|
25
25
|
"publishConfig": {
|
|
26
26
|
"access": "public"
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { PublicKey } from '@dxos/keys';
|
|
6
|
+
import { describe, test } from '@dxos/test';
|
|
7
|
+
import { isNotNullOrUndefined, numericalValues, range } from '@dxos/util';
|
|
8
|
+
|
|
9
|
+
import { Timeframe } from './timeframe';
|
|
10
|
+
|
|
11
|
+
type RandomTimeframeOpts = {
|
|
12
|
+
keys: PublicKey[];
|
|
13
|
+
base?: Timeframe;
|
|
14
|
+
occupancy?: number;
|
|
15
|
+
similarity?: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const createRandomTimeframe = ({ keys, base, similarity = 0.1, occupancy = 0.05 }: RandomTimeframeOpts) => {
|
|
19
|
+
const frames = keys
|
|
20
|
+
.map((key): [PublicKey, number] | undefined => {
|
|
21
|
+
if (base && Math.random() < similarity) {
|
|
22
|
+
const seq = base.get(key);
|
|
23
|
+
return seq !== undefined ? [key, base.get(key)!] : undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (Math.random() < occupancy) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return [key, Math.floor(Math.random() * 10_000)];
|
|
31
|
+
})
|
|
32
|
+
.filter(isNotNullOrUndefined);
|
|
33
|
+
return new Timeframe(frames);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
describe('Bench', () => {
|
|
37
|
+
const NUM_KEYS = 500;
|
|
38
|
+
const NUM_ITERS = 100;
|
|
39
|
+
|
|
40
|
+
const keys = range(NUM_KEYS).map(() => PublicKey.random());
|
|
41
|
+
|
|
42
|
+
test.only('dependencies', async () => {
|
|
43
|
+
const timeframe1 = createRandomTimeframe({ keys });
|
|
44
|
+
const timeframe2 = createRandomTimeframe({ keys, base: timeframe1, similarity: 0.6 });
|
|
45
|
+
|
|
46
|
+
console.log(
|
|
47
|
+
await bench(() => {
|
|
48
|
+
for (let i = 0; i < NUM_ITERS; i++) {
|
|
49
|
+
Timeframe.dependencies(timeframe1, timeframe2);
|
|
50
|
+
}
|
|
51
|
+
}, NUM_ITERS),
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const bench = async (fn: () => void, factor = 1) => {
|
|
57
|
+
const runs: number[] = [];
|
|
58
|
+
|
|
59
|
+
const benchBegin = performance.now();
|
|
60
|
+
while (true) {
|
|
61
|
+
const begin = performance.now();
|
|
62
|
+
fn();
|
|
63
|
+
const end = performance.now();
|
|
64
|
+
const elapsed = end - begin;
|
|
65
|
+
const totalElapsed = end - benchBegin;
|
|
66
|
+
runs.push(elapsed / factor);
|
|
67
|
+
|
|
68
|
+
if (totalElapsed > 1_000) {
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return numericalValues(runs, (x) => x);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/*
|
|
79
|
+
|
|
80
|
+
baseline {
|
|
81
|
+
total: 10.049405800029636,
|
|
82
|
+
count: 36,
|
|
83
|
+
min: 0.27159708000719546,
|
|
84
|
+
max: 0.40789625003933905,
|
|
85
|
+
mean: 0.2791501611119343,
|
|
86
|
+
median: 0.27534582998603585
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
unwrap map {
|
|
90
|
+
total: 9.89743632942438,
|
|
91
|
+
count: 275,
|
|
92
|
+
min: 0.03528792001307011,
|
|
93
|
+
max: 0.08000333003699779,
|
|
94
|
+
mean: 0.0359906775615432,
|
|
95
|
+
median: 0.03549625001847744
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
collocate maps {
|
|
99
|
+
total: 9.782685480117792,
|
|
100
|
+
count: 305,
|
|
101
|
+
min: 0.03119667001068592,
|
|
102
|
+
max: 0.0767849999666214,
|
|
103
|
+
mean: 0.03207437862333702,
|
|
104
|
+
median: 0.03168250001966953
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
*/
|
package/src/timeframe.ts
CHANGED
|
@@ -6,13 +6,17 @@ import { inspect } from 'node:util';
|
|
|
6
6
|
|
|
7
7
|
import { equalsSymbol, Equatable } from '@dxos/debug';
|
|
8
8
|
import { PublicKey } from '@dxos/keys';
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
type Entry = {
|
|
11
|
+
key: PublicKey;
|
|
12
|
+
seq: number;
|
|
13
|
+
};
|
|
10
14
|
|
|
11
15
|
/**
|
|
12
16
|
* A vector clock that implements ordering over a set of feed messages.
|
|
13
17
|
*/
|
|
14
18
|
export class Timeframe implements Equatable {
|
|
15
|
-
private readonly _frames = new
|
|
19
|
+
private readonly _frames = new Map<string, Entry>();
|
|
16
20
|
|
|
17
21
|
constructor(frames: [PublicKey, number][] = []) {
|
|
18
22
|
for (const [key, seq] of frames) {
|
|
@@ -38,18 +42,19 @@ export class Timeframe implements Equatable {
|
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
// TODO(burdon): Rename getFrame.
|
|
41
|
-
get(key: PublicKey) {
|
|
42
|
-
return this._frames.get(key);
|
|
45
|
+
get(key: PublicKey): number | undefined {
|
|
46
|
+
return this._frames.get(key.toHex())?.seq;
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
// TODO(burdon): Rename setFrame.
|
|
46
|
-
set(key: PublicKey,
|
|
47
|
-
|
|
50
|
+
set(key: PublicKey, seq: number) {
|
|
51
|
+
const hex = key.toHex();
|
|
52
|
+
this._frames.set(hex, { key, seq });
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
// TODO(burdon): Change to getter.
|
|
51
56
|
frames(): [PublicKey, number][] {
|
|
52
|
-
return Array.from(this._frames.
|
|
57
|
+
return Array.from(this._frames.values()).map(({ key, seq }) => [key, seq]);
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
// TODO(burdon): Change to getter.
|
|
@@ -67,11 +72,7 @@ export class Timeframe implements Equatable {
|
|
|
67
72
|
* @param keys
|
|
68
73
|
*/
|
|
69
74
|
withoutKeys(keys: PublicKey[]): Timeframe {
|
|
70
|
-
return new Timeframe(
|
|
71
|
-
this.frames().filter(([frameKey]) =>
|
|
72
|
-
keys.every((key) => Buffer.compare(key.asBuffer(), frameKey.asBuffer()) !== 0),
|
|
73
|
-
),
|
|
74
|
-
);
|
|
75
|
+
return new Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => !key.equals(frameKey))));
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
map(fn: (frame: [key: PublicKey, seq: number]) => [PublicKey, number]): Timeframe {
|
|
@@ -82,7 +83,7 @@ export class Timeframe implements Equatable {
|
|
|
82
83
|
* Returns a total amount of messages represented by this timeframe.
|
|
83
84
|
*/
|
|
84
85
|
totalMessages(): number {
|
|
85
|
-
return Array.from(this._frames.values()).reduce((result, seq) => result + seq + 1, 0);
|
|
86
|
+
return Array.from(this._frames.values()).reduce((result, { seq }) => result + seq + 1, 0);
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
/**
|
|
@@ -90,7 +91,7 @@ export class Timeframe implements Equatable {
|
|
|
90
91
|
*/
|
|
91
92
|
newMessages(base: Timeframe) {
|
|
92
93
|
return Array.from(this._frames.entries()).reduce(
|
|
93
|
-
(result, [
|
|
94
|
+
(result, [hex, { seq }]) => result + Math.max(seq - (base._frames.get(hex)?.seq ?? -1), 0),
|
|
94
95
|
0,
|
|
95
96
|
);
|
|
96
97
|
}
|
|
@@ -117,10 +118,10 @@ export class Timeframe implements Equatable {
|
|
|
117
118
|
static merge(...timeframes: Timeframe[]): Timeframe {
|
|
118
119
|
const result = new Timeframe();
|
|
119
120
|
for (const timeframe of timeframes) {
|
|
120
|
-
for (const [
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
result.set(
|
|
121
|
+
for (const [hex, entry] of timeframe._frames) {
|
|
122
|
+
const currentEntry = result._frames.get(hex);
|
|
123
|
+
if (currentEntry === undefined || entry.seq > currentEntry.seq) {
|
|
124
|
+
result._frames.set(hex, entry);
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
}
|
|
@@ -134,10 +135,10 @@ export class Timeframe implements Equatable {
|
|
|
134
135
|
*/
|
|
135
136
|
static dependencies(tf1: Timeframe, tf2: Timeframe): Timeframe {
|
|
136
137
|
const result = new Timeframe();
|
|
137
|
-
for (const [
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
140
|
-
result.set(
|
|
138
|
+
for (const [hex, entry] of tf1._frames) {
|
|
139
|
+
const otherEntry = tf2._frames.get(hex);
|
|
140
|
+
if (otherEntry === undefined || otherEntry.seq < entry.seq) {
|
|
141
|
+
result._frames.set(hex, entry);
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
|