@peerbit/log 3.0.34 → 4.0.0-55cebfe
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/benchmark/append.d.ts +2 -0
- package/dist/benchmark/append.d.ts.map +1 -0
- package/dist/benchmark/append.js +40 -0
- package/dist/benchmark/append.js.map +1 -0
- package/dist/benchmark/memory/index.d.ts +2 -0
- package/dist/benchmark/memory/index.d.ts.map +1 -0
- package/dist/benchmark/memory/index.js +122 -0
- package/dist/benchmark/memory/index.js.map +1 -0
- package/dist/benchmark/memory/insert.d.ts +2 -0
- package/dist/benchmark/memory/insert.d.ts.map +1 -0
- package/dist/benchmark/memory/insert.js +59 -0
- package/dist/benchmark/memory/insert.js.map +1 -0
- package/dist/benchmark/memory/utils.d.ts +13 -0
- package/dist/benchmark/memory/utils.d.ts.map +1 -0
- package/dist/benchmark/memory/utils.js +2 -0
- package/dist/benchmark/memory/utils.js.map +1 -0
- package/dist/benchmark/payload.d.ts +2 -0
- package/dist/benchmark/payload.d.ts.map +1 -0
- package/{lib/esm/__benchmark__/index.js → dist/benchmark/payload.js} +20 -22
- package/dist/benchmark/payload.js.map +1 -0
- package/dist/src/change.d.ts +6 -0
- package/dist/src/change.d.ts.map +1 -0
- package/{lib/esm → dist/src}/clock.d.ts +3 -26
- package/dist/src/clock.d.ts.map +1 -0
- package/{lib/esm → dist/src}/clock.js +30 -39
- package/dist/src/clock.js.map +1 -0
- package/{lib/esm → dist/src}/difference.d.ts +1 -0
- package/dist/src/difference.d.ts.map +1 -0
- package/{lib/esm → dist/src}/encoding.d.ts +2 -1
- package/dist/src/encoding.d.ts.map +1 -0
- package/{lib/esm → dist/src}/encoding.js +2 -2
- package/{lib/esm → dist/src}/encoding.js.map +1 -1
- package/dist/src/entry-index.d.ts +78 -0
- package/dist/src/entry-index.d.ts.map +1 -0
- package/dist/src/entry-index.js +316 -0
- package/dist/src/entry-index.js.map +1 -0
- package/{lib/esm → dist/src}/entry-with-refs.d.ts +2 -1
- package/dist/src/entry-with-refs.d.ts.map +1 -0
- package/{lib/esm → dist/src}/entry.d.ts +22 -18
- package/dist/src/entry.d.ts.map +1 -0
- package/{lib/esm → dist/src}/entry.js +69 -42
- package/dist/src/entry.js.map +1 -0
- package/{lib/esm → dist/src}/find-uniques.d.ts +1 -0
- package/dist/src/find-uniques.d.ts.map +1 -0
- package/{lib/esm → dist/src}/heads-cache.d.ts +4 -3
- package/dist/src/heads-cache.d.ts.map +1 -0
- package/{lib/esm → dist/src}/heads-cache.js +9 -10
- package/dist/src/heads-cache.js.map +1 -0
- package/{lib/esm → dist/src}/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -0
- package/{lib/esm → dist/src}/log-errors.d.ts +1 -0
- package/dist/src/log-errors.d.ts.map +1 -0
- package/dist/src/log-sorting.d.ts +35 -0
- package/dist/src/log-sorting.d.ts.map +1 -0
- package/dist/src/log-sorting.js +105 -0
- package/dist/src/log-sorting.js.map +1 -0
- package/{lib/esm → dist/src}/log.d.ts +78 -56
- package/dist/src/log.d.ts.map +1 -0
- package/{lib/esm → dist/src}/log.js +355 -465
- package/dist/src/log.js.map +1 -0
- package/{lib/esm → dist/src}/logger.d.ts +1 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/{lib/esm → dist/src}/logger.js.map +1 -1
- package/{lib/esm → dist/src}/snapshot.d.ts +5 -4
- package/dist/src/snapshot.d.ts.map +1 -0
- package/{lib/esm → dist/src}/snapshot.js +10 -10
- package/dist/src/snapshot.js.map +1 -0
- package/{lib/esm → dist/src}/trim.d.ts +11 -9
- package/dist/src/trim.d.ts.map +1 -0
- package/{lib/esm → dist/src}/trim.js +46 -35
- package/dist/src/trim.js.map +1 -0
- package/dist/src/utils.d.ts +4 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +12 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +104 -78
- package/src/change.ts +3 -2
- package/src/clock.ts +22 -22
- package/src/encoding.ts +4 -4
- package/src/entry-index.ts +451 -52
- package/src/entry-with-refs.ts +1 -1
- package/src/entry.ts +95 -81
- package/src/heads-cache.ts +33 -29
- package/src/log-sorting.ts +116 -94
- package/src/log.ts +482 -571
- package/src/logger.ts +1 -0
- package/src/snapshot.ts +15 -17
- package/src/trim.ts +81 -50
- package/src/utils.ts +10 -0
- package/lib/esm/__benchmark__/index.d.ts +0 -1
- package/lib/esm/__benchmark__/index.js.map +0 -1
- package/lib/esm/change.d.ts +0 -5
- package/lib/esm/clock.js.map +0 -1
- package/lib/esm/entry-index.d.ts +0 -24
- package/lib/esm/entry-index.js +0 -74
- package/lib/esm/entry-index.js.map +0 -1
- package/lib/esm/entry.js.map +0 -1
- package/lib/esm/heads-cache.js.map +0 -1
- package/lib/esm/heads.d.ts +0 -69
- package/lib/esm/heads.js +0 -157
- package/lib/esm/heads.js.map +0 -1
- package/lib/esm/log-sorting.d.ts +0 -44
- package/lib/esm/log-sorting.js +0 -86
- package/lib/esm/log-sorting.js.map +0 -1
- package/lib/esm/log.js.map +0 -1
- package/lib/esm/snapshot.js.map +0 -1
- package/lib/esm/trim.js.map +0 -1
- package/lib/esm/types.d.ts +0 -6
- package/lib/esm/types.js +0 -23
- package/lib/esm/types.js.map +0 -1
- package/lib/esm/utils.d.ts +0 -2
- package/lib/esm/utils.js +0 -3
- package/lib/esm/utils.js.map +0 -1
- package/lib/esm/values.d.ts +0 -26
- package/lib/esm/values.js +0 -131
- package/lib/esm/values.js.map +0 -1
- package/src/__benchmark__/index.ts +0 -130
- package/src/heads.ts +0 -233
- package/src/types.ts +0 -12
- package/src/values.ts +0 -174
- /package/{lib/esm → dist/src}/change.js +0 -0
- /package/{lib/esm → dist/src}/change.js.map +0 -0
- /package/{lib/esm → dist/src}/difference.js +0 -0
- /package/{lib/esm → dist/src}/difference.js.map +0 -0
- /package/{lib/esm → dist/src}/entry-with-refs.js +0 -0
- /package/{lib/esm → dist/src}/entry-with-refs.js.map +0 -0
- /package/{lib/esm → dist/src}/find-uniques.js +0 -0
- /package/{lib/esm → dist/src}/find-uniques.js.map +0 -0
- /package/{lib/esm → dist/src}/index.js +0 -0
- /package/{lib/esm → dist/src}/index.js.map +0 -0
- /package/{lib/esm → dist/src}/log-errors.js +0 -0
- /package/{lib/esm → dist/src}/log-errors.js.map +0 -0
- /package/{lib/esm → dist/src}/logger.js +0 -0
package/src/clock.ts
CHANGED
|
@@ -22,21 +22,23 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
22
22
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
23
|
SOFTWARE.
|
|
24
24
|
*/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
import {
|
|
26
|
+
field,
|
|
27
|
+
/* , variant */
|
|
28
|
+
} from "@dao-xyz/borsh";
|
|
28
29
|
import { hrtime } from "@peerbit/time";
|
|
30
|
+
import { compare, equals } from "uint8arrays";
|
|
29
31
|
|
|
30
32
|
const hrTimeNow = hrtime.bigint();
|
|
31
33
|
const startTime = BigInt(Date.now()) * BigInt(1e6) - hrTimeNow;
|
|
32
34
|
const bigintTime = () => startTime + hrtime.bigint();
|
|
33
35
|
|
|
34
|
-
export function fromBits(low, high, unsigned, target
|
|
36
|
+
export function fromBits(low: any, high: any, unsigned: any, target?: any) {
|
|
35
37
|
if (target === undefined || target === null) {
|
|
36
38
|
return {
|
|
37
39
|
low: low | 0,
|
|
38
40
|
high: high | 0,
|
|
39
|
-
unsigned: !!unsigned
|
|
41
|
+
unsigned: !!unsigned,
|
|
40
42
|
};
|
|
41
43
|
}
|
|
42
44
|
target.low = low | 0;
|
|
@@ -49,14 +51,14 @@ const n1e6 = BigInt(1e6);
|
|
|
49
51
|
const UINT64_MAX = 18446744073709551615n;
|
|
50
52
|
const UINT32_MAX = 0xffffffff;
|
|
51
53
|
|
|
52
|
-
function bigIntCoerce(input, fallback) {
|
|
54
|
+
function bigIntCoerce(input: any, fallback: any) {
|
|
53
55
|
if (typeof input === "bigint") return input;
|
|
54
56
|
if (typeof input === "number" || typeof input === "string")
|
|
55
57
|
return BigInt(input);
|
|
56
58
|
return fallback;
|
|
57
59
|
}
|
|
58
60
|
|
|
59
|
-
@variant(0)
|
|
61
|
+
/* @variant(0) */
|
|
60
62
|
export class Timestamp {
|
|
61
63
|
@field({ type: "u64" })
|
|
62
64
|
wallTime: bigint;
|
|
@@ -64,11 +66,9 @@ export class Timestamp {
|
|
|
64
66
|
@field({ type: "u32" })
|
|
65
67
|
logical: number;
|
|
66
68
|
|
|
67
|
-
constructor(properties
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
this.logical = properties.logical || 0;
|
|
71
|
-
}
|
|
69
|
+
constructor(properties: { wallTime: bigint; logical?: number }) {
|
|
70
|
+
this.wallTime = properties.wallTime;
|
|
71
|
+
this.logical = properties.logical || 0;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
static compare(a: Timestamp, b: Timestamp) {
|
|
@@ -92,7 +92,7 @@ export class Timestamp {
|
|
|
92
92
|
clone(): Timestamp {
|
|
93
93
|
return new Timestamp({
|
|
94
94
|
wallTime: this.wallTime,
|
|
95
|
-
logical: this.logical
|
|
95
|
+
logical: this.logical,
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -114,14 +114,14 @@ export class HLC {
|
|
|
114
114
|
wallTimeUpperBound?: bigint;
|
|
115
115
|
toleratedForwardClockJump?: bigint;
|
|
116
116
|
last?: Timestamp;
|
|
117
|
-
} = {}
|
|
117
|
+
} = {},
|
|
118
118
|
) {
|
|
119
119
|
this.wallTime = properties.wallTime || bigintTime;
|
|
120
120
|
this.maxOffset = bigIntCoerce(properties.maxOffset, 0n);
|
|
121
121
|
this.wallTimeUpperBound = bigIntCoerce(properties.wallTimeUpperBound, 0n);
|
|
122
122
|
this.toleratedForwardClockJump = bigIntCoerce(
|
|
123
123
|
properties.toleratedForwardClockJump,
|
|
124
|
-
0n
|
|
124
|
+
0n,
|
|
125
125
|
);
|
|
126
126
|
this.last = new Timestamp({ wallTime: this.wallTime() });
|
|
127
127
|
if (properties.last) {
|
|
@@ -180,7 +180,7 @@ export class ClockOffsetError extends Error {
|
|
|
180
180
|
offset / n1e6
|
|
181
181
|
}ms ahead of the wall time, exceeding the 'maxOffset' limit of ${
|
|
182
182
|
maxOffset / n1e6
|
|
183
|
-
}ms
|
|
183
|
+
}ms.`,
|
|
184
184
|
);
|
|
185
185
|
this.offset = offset;
|
|
186
186
|
this.maxOffset = maxOffset;
|
|
@@ -194,7 +194,7 @@ export class WallTimeOverflowError extends Error {
|
|
|
194
194
|
super(
|
|
195
195
|
`The wall time ${time / n1e6}ms exceeds the max time of ${
|
|
196
196
|
maxTime / n1e6
|
|
197
|
-
}ms
|
|
197
|
+
}ms.`,
|
|
198
198
|
);
|
|
199
199
|
this.time = time;
|
|
200
200
|
this.maxTime = maxTime;
|
|
@@ -208,14 +208,14 @@ export class ForwardJumpError extends Error {
|
|
|
208
208
|
super(
|
|
209
209
|
`Detected a forward time jump of ${
|
|
210
210
|
timejump / n1e6
|
|
211
|
-
}ms, which exceed the allowed tolerance of ${tolerance / n1e6}ms
|
|
211
|
+
}ms, which exceed the allowed tolerance of ${tolerance / n1e6}ms.`,
|
|
212
212
|
);
|
|
213
213
|
this.timejump = timejump;
|
|
214
214
|
this.tolerance = tolerance;
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
@variant(0)
|
|
218
|
+
/* @variant(0) */
|
|
219
219
|
export class LamportClock {
|
|
220
220
|
@field({ type: Uint8Array })
|
|
221
221
|
id: Uint8Array;
|
|
@@ -228,13 +228,13 @@ export class LamportClock {
|
|
|
228
228
|
if (!properties.timestamp) {
|
|
229
229
|
this.timestamp = new Timestamp({
|
|
230
230
|
wallTime: bigintTime(),
|
|
231
|
-
logical: 0
|
|
231
|
+
logical: 0,
|
|
232
232
|
});
|
|
233
233
|
} else {
|
|
234
234
|
if (typeof properties.timestamp === "number") {
|
|
235
235
|
this.timestamp = new Timestamp({
|
|
236
236
|
wallTime: bigintTime(),
|
|
237
|
-
logical: properties.timestamp
|
|
237
|
+
logical: properties.timestamp,
|
|
238
238
|
});
|
|
239
239
|
} else {
|
|
240
240
|
this.timestamp = properties.timestamp;
|
|
@@ -245,7 +245,7 @@ export class LamportClock {
|
|
|
245
245
|
clone() {
|
|
246
246
|
return new LamportClock({
|
|
247
247
|
id: this.id,
|
|
248
|
-
timestamp: this.timestamp.clone()
|
|
248
|
+
timestamp: this.timestamp.clone(),
|
|
249
249
|
});
|
|
250
250
|
}
|
|
251
251
|
|
package/src/encoding.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AbstractType, deserialize, serialize } from "@dao-xyz/borsh";
|
|
1
|
+
import { type AbstractType, deserialize, serialize } from "@dao-xyz/borsh";
|
|
2
2
|
|
|
3
3
|
export interface Encoding<T> {
|
|
4
4
|
encoder: (data: T) => Uint8Array;
|
|
@@ -9,19 +9,19 @@ export const NO_ENCODING: Encoding<any> = {
|
|
|
9
9
|
if (obj instanceof Uint8Array === false) {
|
|
10
10
|
throw new Error(
|
|
11
11
|
"With NO_ENCODING only Uint8arrays are allowed, received: " +
|
|
12
|
-
(obj?.["constructor"]?.["name"] || typeof obj)
|
|
12
|
+
(obj?.["constructor"]?.["name"] || typeof obj),
|
|
13
13
|
);
|
|
14
14
|
}
|
|
15
15
|
return obj;
|
|
16
16
|
},
|
|
17
17
|
decoder: (bytes: Uint8Array) => {
|
|
18
18
|
return bytes;
|
|
19
|
-
}
|
|
19
|
+
},
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export const BORSH_ENCODING = <T>(clazz: AbstractType<T>): Encoding<T> => {
|
|
23
23
|
return {
|
|
24
24
|
decoder: (bytes: Uint8Array) => deserialize(bytes, clazz),
|
|
25
|
-
encoder: (data: any) => serialize(data)
|
|
25
|
+
encoder: (data: any) => serialize(data),
|
|
26
26
|
};
|
|
27
27
|
};
|
package/src/entry-index.ts
CHANGED
|
@@ -1,36 +1,291 @@
|
|
|
1
|
+
import { deserialize, serialize } from "@dao-xyz/borsh";
|
|
2
|
+
import { type Blocks } from "@peerbit/blocks-interface";
|
|
1
3
|
import { Cache } from "@peerbit/cache";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
+
import type { PublicSignKey } from "@peerbit/crypto";
|
|
5
|
+
import {
|
|
6
|
+
BoolQuery,
|
|
7
|
+
CountRequest,
|
|
8
|
+
DeleteRequest,
|
|
9
|
+
type Index,
|
|
10
|
+
Not,
|
|
11
|
+
Or,
|
|
12
|
+
type Query,
|
|
13
|
+
SearchRequest,
|
|
14
|
+
type Shape,
|
|
15
|
+
Sort,
|
|
16
|
+
SortDirection,
|
|
17
|
+
StringMatch,
|
|
18
|
+
StringMatchMethod,
|
|
19
|
+
SumRequest,
|
|
20
|
+
iterate,
|
|
21
|
+
toId,
|
|
22
|
+
} from "@peerbit/indexer-interface";
|
|
23
|
+
import {
|
|
24
|
+
Entry,
|
|
25
|
+
EntryType,
|
|
26
|
+
type ShallowEntry,
|
|
27
|
+
type ShallowOrFullEntry,
|
|
28
|
+
} from "./entry.js";
|
|
29
|
+
import type { SortFn } from "./log-sorting.js";
|
|
4
30
|
import { logger } from "./logger.js";
|
|
5
|
-
|
|
31
|
+
|
|
32
|
+
export type ResultsIterator<T> = {
|
|
33
|
+
close: () => void | Promise<void>;
|
|
34
|
+
next: (number: number) => T[] | Promise<T[]>;
|
|
35
|
+
done: () => boolean;
|
|
36
|
+
all(): T[] | Promise<T[]>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const ENTRY_CACHE_MAX_SIZE = 10; // TODO as param for log
|
|
40
|
+
|
|
41
|
+
type ResolveFullyOptions =
|
|
42
|
+
| true
|
|
43
|
+
| {
|
|
44
|
+
type: "full";
|
|
45
|
+
replicate?: boolean;
|
|
46
|
+
signal?: AbortSignal;
|
|
47
|
+
timeout?: number;
|
|
48
|
+
ignoreMissing?: boolean;
|
|
49
|
+
};
|
|
50
|
+
type ResolveShapeOptions = { type: "shape"; shape: Shape };
|
|
51
|
+
export type MaybeResolveOptions =
|
|
52
|
+
| false
|
|
53
|
+
| ResolveFullyOptions
|
|
54
|
+
| ResolveShapeOptions;
|
|
55
|
+
export type ReturnTypeFromResolveOptions<
|
|
56
|
+
R extends MaybeResolveOptions,
|
|
57
|
+
T,
|
|
58
|
+
> = R extends false | undefined
|
|
59
|
+
? ShallowEntry
|
|
60
|
+
: R extends { type: "shape" }
|
|
61
|
+
? any
|
|
62
|
+
: Entry<T>;
|
|
6
63
|
|
|
7
64
|
export class EntryIndex<T> {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
constructor(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
65
|
+
private cache: Cache<Entry<T>>;
|
|
66
|
+
private sortReversed: Sort[];
|
|
67
|
+
private initialied = false;
|
|
68
|
+
private _length: number;
|
|
69
|
+
private insertionPromises: Map<string, Promise<void>>;
|
|
70
|
+
constructor(
|
|
71
|
+
readonly properties: {
|
|
72
|
+
store: Blocks;
|
|
73
|
+
publicKey: PublicSignKey;
|
|
74
|
+
init: (entry: Entry<T>) => void;
|
|
75
|
+
cache?: Cache<Entry<T>>;
|
|
76
|
+
index: Index<ShallowEntry>;
|
|
77
|
+
sort: SortFn;
|
|
78
|
+
onGidRemoved?: (gid: string[]) => Promise<void> | void;
|
|
79
|
+
},
|
|
80
|
+
) {
|
|
81
|
+
this.sortReversed = properties.sort.sort.map((x) =>
|
|
82
|
+
deserialize(serialize(x), Sort),
|
|
83
|
+
);
|
|
84
|
+
this.sortReversed.map(
|
|
85
|
+
(x) =>
|
|
86
|
+
(x.direction =
|
|
87
|
+
x.direction === SortDirection.DESC
|
|
88
|
+
? SortDirection.ASC
|
|
89
|
+
: SortDirection.DESC),
|
|
90
|
+
);
|
|
91
|
+
this.cache = properties.cache ?? new Cache({ max: ENTRY_CACHE_MAX_SIZE });
|
|
92
|
+
this._length = 0;
|
|
93
|
+
this.insertionPromises = new Map();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
getHeads<R extends MaybeResolveOptions = false>(
|
|
97
|
+
gid?: string,
|
|
98
|
+
resolve: R = false as R,
|
|
99
|
+
): ResultsIterator<ReturnTypeFromResolveOptions<R, T>> {
|
|
100
|
+
const query: Query[] = [];
|
|
101
|
+
query.push(new BoolQuery({ key: "head", value: true }));
|
|
102
|
+
if (gid) {
|
|
103
|
+
query.push(
|
|
104
|
+
new StringMatch({
|
|
105
|
+
key: ["meta", "gid"],
|
|
106
|
+
value: gid,
|
|
107
|
+
caseInsensitive: false,
|
|
108
|
+
method: StringMatchMethod.exact,
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return this.query(query, undefined, resolve);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
getHasNext<R extends MaybeResolveOptions>(
|
|
116
|
+
next: string,
|
|
117
|
+
resolve?: R,
|
|
118
|
+
): ResultsIterator<ReturnTypeFromResolveOptions<R, T>> {
|
|
119
|
+
const query: Query[] = [
|
|
120
|
+
new StringMatch({
|
|
121
|
+
key: ["meta", "next"],
|
|
122
|
+
value: next,
|
|
123
|
+
caseInsensitive: false,
|
|
124
|
+
method: StringMatchMethod.exact,
|
|
125
|
+
}),
|
|
126
|
+
];
|
|
127
|
+
return this.query(query, undefined, resolve);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
countHasNext(next: string, excludeHash: string | undefined = undefined) {
|
|
131
|
+
const query: Query[] = [
|
|
132
|
+
new StringMatch({
|
|
133
|
+
key: ["meta", "next"],
|
|
134
|
+
value: next,
|
|
135
|
+
caseInsensitive: false,
|
|
136
|
+
method: StringMatchMethod.exact,
|
|
137
|
+
}),
|
|
138
|
+
];
|
|
139
|
+
if (excludeHash) {
|
|
140
|
+
query.push(
|
|
141
|
+
new Not(
|
|
142
|
+
new StringMatch({
|
|
143
|
+
key: ["hash"],
|
|
144
|
+
value: excludeHash,
|
|
145
|
+
caseInsensitive: false,
|
|
146
|
+
method: StringMatchMethod.exact,
|
|
147
|
+
}),
|
|
148
|
+
),
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
return this.properties.index.count(new CountRequest({ query }));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
query<R extends MaybeResolveOptions>(
|
|
155
|
+
query: Query[],
|
|
156
|
+
sort = this.properties.sort.sort,
|
|
157
|
+
options?: R,
|
|
158
|
+
): ResultsIterator<ReturnTypeFromResolveOptions<R, T>> {
|
|
159
|
+
const iterator = iterate(
|
|
160
|
+
this.properties.index,
|
|
161
|
+
new SearchRequest({ query, sort }),
|
|
162
|
+
);
|
|
163
|
+
let resolveInFull = options
|
|
164
|
+
? options === true
|
|
165
|
+
? true
|
|
166
|
+
: options.type === "full"
|
|
167
|
+
: false;
|
|
168
|
+
let resolveInFullOptions: ResolveFullyOptions | undefined = resolveInFull
|
|
169
|
+
? (options as ResolveFullyOptions)
|
|
170
|
+
: undefined;
|
|
171
|
+
let nextShape = resolveInFull
|
|
172
|
+
? ({ hash: true } as const)
|
|
173
|
+
: ((options as { shape: Shape })?.shape as Shape);
|
|
174
|
+
|
|
175
|
+
const next = async (
|
|
176
|
+
amount: number,
|
|
177
|
+
): Promise<ReturnTypeFromResolveOptions<R, T>[]> => {
|
|
178
|
+
const results = await iterator.next(amount, { shape: nextShape });
|
|
179
|
+
if (resolveInFull) {
|
|
180
|
+
const maybeResolved = await Promise.all(
|
|
181
|
+
results.results.map((x) =>
|
|
182
|
+
this.resolve(x.value.hash, resolveInFullOptions),
|
|
183
|
+
),
|
|
184
|
+
);
|
|
185
|
+
return maybeResolved.filter((x) => !!x) as ReturnTypeFromResolveOptions<
|
|
186
|
+
R,
|
|
187
|
+
T
|
|
188
|
+
>[];
|
|
189
|
+
} else {
|
|
190
|
+
return results.results.map(
|
|
191
|
+
(x) => x.value,
|
|
192
|
+
) as ReturnTypeFromResolveOptions<R, T>[];
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
close: iterator.close,
|
|
198
|
+
done: iterator.done,
|
|
199
|
+
next,
|
|
200
|
+
all: async () => {
|
|
201
|
+
const results: ReturnTypeFromResolveOptions<R, T>[] = [];
|
|
202
|
+
while (!iterator.done()) {
|
|
203
|
+
for (const element of await next(100)) {
|
|
204
|
+
results.push(element);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
await iterator.close();
|
|
208
|
+
return results;
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async getOldest<
|
|
214
|
+
T extends boolean,
|
|
215
|
+
R = T extends true ? Entry<any> : ShallowEntry,
|
|
216
|
+
>(resolve?: T): Promise<R | undefined> {
|
|
217
|
+
const iterator = this.query([], this.properties.sort.sort, resolve);
|
|
218
|
+
const results = await iterator.next(1);
|
|
219
|
+
await iterator.close();
|
|
220
|
+
return results[0] as R;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async getNewest<
|
|
224
|
+
T extends boolean,
|
|
225
|
+
R = T extends true ? Entry<any> : ShallowEntry,
|
|
226
|
+
>(resolve?: T): Promise<R | undefined> {
|
|
227
|
+
const iterator = this.query([], this.sortReversed, resolve);
|
|
228
|
+
const results = await iterator.next(1);
|
|
229
|
+
await iterator.close();
|
|
230
|
+
return results[0] as R;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async getBefore<
|
|
234
|
+
T extends boolean,
|
|
235
|
+
R = T extends true ? Entry<any> : ShallowEntry,
|
|
236
|
+
>(before: ShallowOrFullEntry<any>, resolve?: T): Promise<R | undefined> {
|
|
237
|
+
const iterator = this.query(
|
|
238
|
+
this.properties.sort.before(before),
|
|
239
|
+
this.sortReversed,
|
|
240
|
+
resolve,
|
|
241
|
+
);
|
|
242
|
+
const results = await iterator.next(1);
|
|
243
|
+
await iterator.close();
|
|
244
|
+
return results[0] as R;
|
|
245
|
+
}
|
|
246
|
+
async getAfter<
|
|
247
|
+
T extends boolean,
|
|
248
|
+
R = T extends true ? Entry<any> : ShallowEntry,
|
|
249
|
+
>(before: ShallowOrFullEntry<any>, resolve?: T): Promise<R | undefined> {
|
|
250
|
+
const iterator = this.query(
|
|
251
|
+
this.properties.sort.after(before),
|
|
252
|
+
this.properties.sort.sort,
|
|
253
|
+
resolve,
|
|
254
|
+
);
|
|
255
|
+
const results = await iterator.next(1);
|
|
256
|
+
await iterator.close();
|
|
257
|
+
|
|
258
|
+
return results[0] as R;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async get(k: string, options?: ResolveFullyOptions) {
|
|
262
|
+
return this.resolve(k, options);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async getShallow(k: string) {
|
|
266
|
+
return this.properties.index.get(toId(k));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async has(k: string) {
|
|
270
|
+
const result = await this.properties.index.get(toId(k), {
|
|
271
|
+
shape: { hash: true },
|
|
272
|
+
});
|
|
273
|
+
return result != null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async put(
|
|
277
|
+
entry: Entry<any>,
|
|
278
|
+
properties: { unique: boolean; isHead: boolean; toMultiHash: boolean },
|
|
279
|
+
) {
|
|
280
|
+
if (properties.toMultiHash) {
|
|
281
|
+
const existingHash = entry.hash;
|
|
282
|
+
entry.hash = undefined as any;
|
|
28
283
|
try {
|
|
29
|
-
const hash = await Entry.toMultihash(this.
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
} else if (existingHash !==
|
|
284
|
+
const hash = await Entry.toMultihash(this.properties.store, entry);
|
|
285
|
+
entry.hash = existingHash;
|
|
286
|
+
if (entry.hash === undefined) {
|
|
287
|
+
entry.hash = hash; // can happen if you sync entries that you load directly from ipfs
|
|
288
|
+
} else if (existingHash !== entry.hash) {
|
|
34
289
|
logger.error("Head hash didn't match the contents");
|
|
35
290
|
throw new Error("Head hash didn't match the contents");
|
|
36
291
|
}
|
|
@@ -38,42 +293,192 @@ export class EntryIndex<T> {
|
|
|
38
293
|
logger.error(error);
|
|
39
294
|
throw error;
|
|
40
295
|
}
|
|
296
|
+
} else {
|
|
297
|
+
if (!entry.hash) {
|
|
298
|
+
throw new Error("Missing hash");
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const existingPromise = this.insertionPromises.get(entry.hash);
|
|
303
|
+
if (existingPromise) {
|
|
304
|
+
return existingPromise;
|
|
305
|
+
} else {
|
|
306
|
+
const fn = async () => {
|
|
307
|
+
this.cache.add(entry.hash, entry);
|
|
308
|
+
|
|
309
|
+
if (properties.unique === true || !(await this.has(entry.hash))) {
|
|
310
|
+
this._length++;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
await this.properties.index.put(entry.toShallow(properties.isHead));
|
|
314
|
+
|
|
315
|
+
// check if gids has been shadowed, by query all nexts that have a different gid
|
|
316
|
+
if (this.properties.onGidRemoved && entry.meta.next.length > 0) {
|
|
317
|
+
let nextMatches: Query[] = [];
|
|
318
|
+
|
|
319
|
+
for (const next of entry.meta.next) {
|
|
320
|
+
nextMatches.push(
|
|
321
|
+
new StringMatch({
|
|
322
|
+
key: ["hash"],
|
|
323
|
+
value: next,
|
|
324
|
+
caseInsensitive: false,
|
|
325
|
+
method: StringMatchMethod.exact,
|
|
326
|
+
}),
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const nextsWithOthersGids: { hash: string; meta: { gid: string } }[] =
|
|
331
|
+
await this.query(
|
|
332
|
+
[
|
|
333
|
+
new Or(nextMatches),
|
|
334
|
+
new Not(
|
|
335
|
+
new StringMatch({
|
|
336
|
+
key: ["meta", "gid"],
|
|
337
|
+
value: entry.meta.gid,
|
|
338
|
+
}),
|
|
339
|
+
),
|
|
340
|
+
],
|
|
341
|
+
undefined,
|
|
342
|
+
{ type: "shape", shape: { hash: true, meta: { gid: true } } },
|
|
343
|
+
).all();
|
|
344
|
+
|
|
345
|
+
let shadowedGids = new Set<string>();
|
|
346
|
+
for (const next of nextsWithOthersGids) {
|
|
347
|
+
// check that this entry is not referenced by other
|
|
348
|
+
const nexts = await this.countHasNext(next.hash, entry.hash);
|
|
349
|
+
if (nexts > 0) {
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
shadowedGids.add(next.meta.gid);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (shadowedGids.size > 0) {
|
|
356
|
+
this.properties.onGidRemoved?.([...shadowedGids]);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// mark all next entries as not heads
|
|
361
|
+
await this.privateUpdateNextHeadProperty(entry, false);
|
|
362
|
+
|
|
363
|
+
this.insertionPromises.delete(entry.hash);
|
|
364
|
+
};
|
|
365
|
+
const promise = fn();
|
|
366
|
+
this.insertionPromises.set(entry.hash, promise);
|
|
367
|
+
return promise;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
async delete(k: string) {
|
|
372
|
+
this.cache.del(k);
|
|
373
|
+
|
|
374
|
+
let shallow = (await this.getShallow(k))?.value;
|
|
375
|
+
if (!shallow) {
|
|
376
|
+
return; // already deleted
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
let deleted = await this.properties.index.del(
|
|
380
|
+
new DeleteRequest({ query: { hash: k } }),
|
|
381
|
+
);
|
|
382
|
+
await this.properties.store.rm(k);
|
|
383
|
+
|
|
384
|
+
if (deleted.length > 0) {
|
|
385
|
+
this._length -= deleted.length;
|
|
386
|
+
|
|
387
|
+
// mark all next entries as new heads
|
|
388
|
+
await this.privateUpdateNextHeadProperty(shallow, true);
|
|
389
|
+
return shallow;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async getMemoryUsage() {
|
|
394
|
+
return this.properties.index.sum(new SumRequest({ key: "payloadSize" }));
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
private async privateUpdateNextHeadProperty(
|
|
398
|
+
from: ShallowEntry | Entry<any>,
|
|
399
|
+
isHead: boolean,
|
|
400
|
+
) {
|
|
401
|
+
if (from.meta.type === EntryType.CUT) {
|
|
402
|
+
// if the next is a cut, we can't update it, since it's not in the index
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
for (const next of from.meta.next) {
|
|
407
|
+
const indexedEntry = await this.properties.index.get(toId(next));
|
|
408
|
+
|
|
409
|
+
if (!indexedEntry) {
|
|
410
|
+
continue; // we could end up here because another entry with same next ref is of CUT and has removed it from the index
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (isHead) {
|
|
414
|
+
const noPointersToNext = (await this.countHasNext(next)) === 0;
|
|
415
|
+
if (noPointersToNext) {
|
|
416
|
+
indexedEntry.value.head = true;
|
|
417
|
+
if (indexedEntry) {
|
|
418
|
+
await this.properties.index.put(indexedEntry.value);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
} else {
|
|
422
|
+
indexedEntry.value.head = false;
|
|
423
|
+
if (indexedEntry) {
|
|
424
|
+
await this.properties.index.put(indexedEntry.value);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
async clear() {
|
|
431
|
+
const iterator = await this.query([], undefined, false);
|
|
432
|
+
while (!iterator.done()) {
|
|
433
|
+
const results = await iterator.next(100);
|
|
434
|
+
for (const result of results) {
|
|
435
|
+
await this.delete(result.hash);
|
|
436
|
+
}
|
|
41
437
|
}
|
|
42
|
-
this.
|
|
43
|
-
this.
|
|
438
|
+
await this.properties.index.drop();
|
|
439
|
+
await this.properties.index.start();
|
|
440
|
+
this.cache.clear();
|
|
44
441
|
}
|
|
45
|
-
|
|
46
|
-
|
|
442
|
+
|
|
443
|
+
get length() {
|
|
444
|
+
if (!this.initialied) {
|
|
445
|
+
throw new Error("Not initialized");
|
|
446
|
+
}
|
|
447
|
+
return this._length;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
async init() {
|
|
451
|
+
this._length = await this.properties.index.getSize();
|
|
452
|
+
this.initialied = true;
|
|
47
453
|
}
|
|
48
454
|
|
|
49
|
-
async
|
|
455
|
+
private async resolve(
|
|
50
456
|
k: string,
|
|
51
|
-
options?:
|
|
457
|
+
options?: ResolveFullyOptions,
|
|
52
458
|
): Promise<Entry<T> | undefined> {
|
|
53
|
-
|
|
54
|
-
|
|
459
|
+
let coercedOptions = typeof options === "object" ? options : undefined;
|
|
460
|
+
if (await this.has(k)) {
|
|
461
|
+
let mem = this.cache.get(k);
|
|
55
462
|
if (mem === undefined) {
|
|
56
|
-
mem = await this.
|
|
463
|
+
mem = await this.resolveFromStore(k, coercedOptions);
|
|
57
464
|
if (mem) {
|
|
58
|
-
this.
|
|
465
|
+
this.properties.init(mem);
|
|
59
466
|
mem.hash = k;
|
|
467
|
+
} else if (coercedOptions?.ignoreMissing !== true) {
|
|
468
|
+
throw new Error("Failed to load entry from head with hash: " + k);
|
|
60
469
|
}
|
|
61
|
-
this.
|
|
470
|
+
this.cache.add(k, mem ?? undefined);
|
|
62
471
|
}
|
|
63
472
|
return mem ? mem : undefined;
|
|
64
473
|
}
|
|
65
474
|
return undefined;
|
|
66
475
|
}
|
|
67
476
|
|
|
68
|
-
|
|
69
|
-
return this._index.get(k);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private async getFromStore(
|
|
477
|
+
private async resolveFromStore(
|
|
73
478
|
k: string,
|
|
74
|
-
options?: { replicate?: boolean; timeout?: number }
|
|
479
|
+
options?: { signal?: AbortSignal; replicate?: boolean; timeout?: number },
|
|
75
480
|
): Promise<Entry<T> | null> {
|
|
76
|
-
const value = await this.
|
|
481
|
+
const value = await this.properties.store.get(k, options);
|
|
77
482
|
if (value) {
|
|
78
483
|
const entry = deserialize(value, Entry);
|
|
79
484
|
entry.size = value.length;
|
|
@@ -81,10 +486,4 @@ export class EntryIndex<T> {
|
|
|
81
486
|
}
|
|
82
487
|
return null;
|
|
83
488
|
}
|
|
84
|
-
|
|
85
|
-
async delete(k: string) {
|
|
86
|
-
this._cache.del(k);
|
|
87
|
-
this._index.delete(k);
|
|
88
|
-
return this._blocks.rm(k);
|
|
89
|
-
}
|
|
90
489
|
}
|