@peerbit/log 3.0.34-aa577a5 → 3.0.34-cccc078
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/{index.d.ts.map → memory/index.d.ts.map} +1 -1
- 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/dist/benchmark/{index.js → payload.js} +14 -14
- package/dist/benchmark/payload.js.map +1 -0
- package/dist/src/change.d.ts +2 -2
- package/dist/src/change.d.ts.map +1 -1
- package/dist/src/change.js +1 -1
- package/dist/src/change.js.map +1 -1
- package/dist/src/clock.d.ts +0 -24
- package/dist/src/clock.d.ts.map +1 -1
- package/dist/src/clock.js +28 -35
- package/dist/src/clock.js.map +1 -1
- package/dist/src/encoding.d.ts.map +1 -1
- package/dist/src/encoding.js +2 -2
- package/dist/src/encoding.js.map +1 -1
- package/dist/src/entry-index.d.ts +70 -17
- package/dist/src/entry-index.d.ts.map +1 -1
- package/dist/src/entry-index.js +281 -41
- package/dist/src/entry-index.js.map +1 -1
- package/dist/src/entry-with-refs.d.ts +1 -1
- package/dist/src/entry-with-refs.d.ts.map +1 -1
- package/dist/src/entry-with-refs.js +1 -1
- package/dist/src/entry-with-refs.js.map +1 -1
- package/dist/src/entry.d.ts +18 -15
- package/dist/src/entry.d.ts.map +1 -1
- package/dist/src/entry.js +62 -36
- package/dist/src/entry.js.map +1 -1
- package/dist/src/find-uniques.d.ts.map +1 -1
- package/dist/src/heads-cache.d.ts +1 -1
- package/dist/src/heads-cache.d.ts.map +1 -1
- package/dist/src/heads-cache.js +6 -7
- package/dist/src/heads-cache.js.map +1 -1
- package/dist/src/log-sorting.d.ts +27 -37
- package/dist/src/log-sorting.d.ts.map +1 -1
- package/dist/src/log-sorting.js +92 -74
- package/dist/src/log-sorting.js.map +1 -1
- package/dist/src/log.d.ts +71 -54
- package/dist/src/log.d.ts.map +1 -1
- package/dist/src/log.js +349 -468
- package/dist/src/log.js.map +1 -1
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/logger.js.map +1 -1
- package/dist/src/snapshot.d.ts +2 -2
- package/dist/src/snapshot.d.ts.map +1 -1
- package/dist/src/snapshot.js +5 -5
- package/dist/src/snapshot.js.map +1 -1
- package/dist/src/trim.d.ts +9 -8
- package/dist/src/trim.d.ts.map +1 -1
- package/dist/src/trim.js +43 -40
- package/dist/src/trim.js.map +1 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +1 -1
- package/dist/src/utils.js.map +1 -1
- package/package.json +15 -13
- package/src/change.ts +3 -2
- package/src/clock.ts +25 -19
- package/src/encoding.ts +3 -3
- package/src/entry-index.ts +451 -52
- package/src/entry-with-refs.ts +1 -1
- package/src/entry.ts +89 -72
- package/src/heads-cache.ts +27 -21
- package/src/log-sorting.ts +116 -94
- package/src/log.ts +465 -564
- package/src/logger.ts +1 -0
- package/src/snapshot.ts +10 -10
- package/src/trim.ts +75 -50
- package/src/utils.ts +6 -8
- package/dist/benchmark/index.js.map +0 -1
- package/dist/src/heads.d.ts +0 -70
- package/dist/src/heads.d.ts.map +0 -1
- package/dist/src/heads.js +0 -164
- package/dist/src/heads.js.map +0 -1
- package/dist/src/types.d.ts +0 -7
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/types.js +0 -21
- package/dist/src/types.js.map +0 -1
- package/dist/src/values.d.ts +0 -27
- package/dist/src/values.d.ts.map +0 -1
- package/dist/src/values.js +0 -134
- package/dist/src/values.js.map +0 -1
- package/src/heads.ts +0 -233
- package/src/types.ts +0 -10
- package/src/values.ts +0 -174
- /package/dist/benchmark/{index.d.ts → memory/index.d.ts} +0 -0
package/dist/src/log.js
CHANGED
|
@@ -8,50 +8,53 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
10
|
var Log_1;
|
|
11
|
-
import {
|
|
12
|
-
import { Cache } from "@peerbit/cache";
|
|
11
|
+
import { deserialize, field, fixedArray, variant } from "@dao-xyz/borsh";
|
|
13
12
|
import {} from "@peerbit/any-store";
|
|
14
|
-
import {
|
|
13
|
+
import { cidifyString } from "@peerbit/blocks-interface";
|
|
14
|
+
import { SignatureWithKey, X25519Keypair, randomBytes, sha256Base64Sync, } from "@peerbit/crypto";
|
|
15
|
+
import {} from "@peerbit/indexer-interface";
|
|
16
|
+
import { create } from "@peerbit/indexer-sqlite3";
|
|
17
|
+
import {} from "@peerbit/keychain";
|
|
18
|
+
import {} from "./change.js";
|
|
19
|
+
import { LamportClock as Clock, HLC, LamportClock, Timestamp, } from "./clock.js";
|
|
20
|
+
import { NO_ENCODING } from "./encoding.js";
|
|
21
|
+
import { EntryIndex, } from "./entry-index.js";
|
|
22
|
+
import {} from "./entry-with-refs.js";
|
|
23
|
+
import { Entry, EntryType, Payload, ShallowEntry, } from "./entry.js";
|
|
24
|
+
import { findUniques } from "./find-uniques.js";
|
|
15
25
|
import * as LogError from "./log-errors.js";
|
|
16
26
|
import * as Sorting from "./log-sorting.js";
|
|
17
|
-
import { findUniques } from "./find-uniques.js";
|
|
18
|
-
import { Entry, Payload, EntryType } from "./entry.js";
|
|
19
|
-
import { HLC, LamportClock as Clock, LamportClock, Timestamp } from "./clock.js";
|
|
20
|
-
import { deserialize, field, fixedArray, variant } from "@dao-xyz/borsh";
|
|
21
|
-
import { NO_ENCODING } from "./encoding.js";
|
|
22
|
-
import { HeadsIndex } from "./heads.js";
|
|
23
|
-
import { Values } from "./values.js";
|
|
24
27
|
import { Trim } from "./trim.js";
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
import {} from "@peerbit/keychain";
|
|
31
|
-
const { LastWriteWins, NoZeroes } = Sorting;
|
|
32
|
-
const ENTRY_CACHE_MAX = 1000; // TODO as param
|
|
28
|
+
const { LastWriteWins } = Sorting;
|
|
29
|
+
export const ENTRY_JOIN_SHAPE = {
|
|
30
|
+
hash: true,
|
|
31
|
+
meta: { type: true, next: true, gid: true, clock: true },
|
|
32
|
+
};
|
|
33
33
|
let Log = Log_1 = class Log {
|
|
34
34
|
_id;
|
|
35
|
-
_sortFn;
|
|
35
|
+
/* private _sortFn!: Sorting.ISortFunction; */
|
|
36
36
|
_storage;
|
|
37
37
|
_hlc;
|
|
38
38
|
// Identity
|
|
39
39
|
_identity;
|
|
40
40
|
// Keeping track of entries
|
|
41
41
|
_entryIndex;
|
|
42
|
-
_headsIndex
|
|
43
|
-
|
|
42
|
+
/* private _headsIndex!: HeadsIndex<T>;
|
|
43
|
+
private _values!: Values<T>;
|
|
44
|
+
*/
|
|
44
45
|
// Index of all next pointers in this log
|
|
45
|
-
_nextsIndex
|
|
46
|
+
/* private _nextsIndex!: Map<string, Set<string>>; */
|
|
46
47
|
_keychain;
|
|
47
48
|
_encoding;
|
|
48
49
|
_trim;
|
|
49
|
-
_entryCache;
|
|
50
50
|
_canAppend;
|
|
51
51
|
_onChange;
|
|
52
52
|
_closed = true;
|
|
53
|
-
|
|
53
|
+
_closeController;
|
|
54
|
+
_loadedOnce = false;
|
|
55
|
+
_indexer;
|
|
54
56
|
_joining; // entry hashes that are currently joining into this log
|
|
57
|
+
_sortFn;
|
|
55
58
|
constructor(properties) {
|
|
56
59
|
this._id = properties?.id || randomBytes(32);
|
|
57
60
|
}
|
|
@@ -65,18 +68,13 @@ let Log = Log_1 = class Log {
|
|
|
65
68
|
if (this.closed === false) {
|
|
66
69
|
throw new Error("Already open");
|
|
67
70
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
sortFn = sortFn;
|
|
74
|
-
this._sortFn = NoZeroes(sortFn);
|
|
71
|
+
this._closeController = new AbortController();
|
|
72
|
+
const { encoding, trim, keychain, indexer, onGidRemoved, sortFn } = options;
|
|
73
|
+
// TODO do correctly with tie breaks
|
|
74
|
+
this._sortFn = sortFn || LastWriteWins;
|
|
75
75
|
this._storage = store;
|
|
76
|
-
this.
|
|
77
|
-
|
|
78
|
-
await this._memory.open();
|
|
79
|
-
}
|
|
76
|
+
this._indexer = indexer || (await create());
|
|
77
|
+
await this._indexer.start?.();
|
|
80
78
|
this._encoding = encoding || NO_ENCODING;
|
|
81
79
|
this._joining = new Map();
|
|
82
80
|
// Identity
|
|
@@ -85,47 +83,30 @@ let Log = Log_1 = class Log {
|
|
|
85
83
|
this._keychain = keychain;
|
|
86
84
|
// Clock
|
|
87
85
|
this._hlc = new HLC();
|
|
88
|
-
this._nextsIndex = new Map();
|
|
89
86
|
const id = this.id;
|
|
90
87
|
if (!id) {
|
|
91
88
|
throw new Error("Id not set");
|
|
92
89
|
}
|
|
93
|
-
this._headsIndex = new HeadsIndex(id);
|
|
94
|
-
await this._headsIndex.init(this, { onGidRemoved });
|
|
95
|
-
this._entryCache = new Cache({ max: ENTRY_CACHE_MAX });
|
|
96
90
|
this._entryIndex = new EntryIndex({
|
|
97
91
|
store: this._storage,
|
|
98
92
|
init: (e) => e.init(this),
|
|
99
|
-
|
|
93
|
+
onGidRemoved,
|
|
94
|
+
index: await (await this._indexer.scope("heads")).init({ schema: ShallowEntry }),
|
|
95
|
+
publicKey: this._identity.publicKey,
|
|
96
|
+
sort: this._sortFn,
|
|
100
97
|
});
|
|
101
|
-
|
|
98
|
+
await this._entryIndex.init();
|
|
99
|
+
/* this._values = new Values(this._entryIndex, this._sortFn); */
|
|
102
100
|
this._trim = new Trim({
|
|
103
|
-
|
|
101
|
+
index: this._entryIndex,
|
|
104
102
|
deleteNode: async (node) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (entry) {
|
|
110
|
-
this.values.deleteNode(node);
|
|
111
|
-
await Promise.all([
|
|
112
|
-
this.headsIndex.del(this.entryIndex.getShallow(node.value)),
|
|
113
|
-
this.entryIndex.delete(node.value)
|
|
114
|
-
]);
|
|
115
|
-
this.nextsIndex.delete(node.value);
|
|
116
|
-
await this.blocks.rm(node.value);
|
|
117
|
-
}
|
|
118
|
-
const b = this.values.length;
|
|
119
|
-
if (a === b) {
|
|
120
|
-
/* throw new Error(
|
|
121
|
-
"Unexpected miss match between log size and entry index size: " +
|
|
122
|
-
this.values.length +
|
|
123
|
-
this.entryIndex._index.size
|
|
124
|
-
); */
|
|
125
|
-
}
|
|
126
|
-
return entry;
|
|
103
|
+
const resolved = await this.get(node.hash);
|
|
104
|
+
await this._entryIndex.delete(node.hash);
|
|
105
|
+
await this._storage.rm(node.hash);
|
|
106
|
+
return resolved;
|
|
127
107
|
},
|
|
128
|
-
|
|
108
|
+
sortFn: this._sortFn,
|
|
109
|
+
getLength: () => this.length,
|
|
129
110
|
}, trim);
|
|
130
111
|
this._canAppend = async (entry) => {
|
|
131
112
|
if (options?.canAppend) {
|
|
@@ -137,6 +118,7 @@ let Log = Log_1 = class Log {
|
|
|
137
118
|
};
|
|
138
119
|
this._onChange = options?.onChange;
|
|
139
120
|
this._closed = false;
|
|
121
|
+
this._closeController = new AbortController();
|
|
140
122
|
}
|
|
141
123
|
_idString;
|
|
142
124
|
get idString() {
|
|
@@ -162,13 +144,10 @@ let Log = Log_1 = class Log {
|
|
|
162
144
|
* Returns the length of the log.
|
|
163
145
|
*/
|
|
164
146
|
get length() {
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
get values() {
|
|
168
|
-
if (this.closed) {
|
|
147
|
+
if (this._closed) {
|
|
169
148
|
throw new Error("Closed");
|
|
170
149
|
}
|
|
171
|
-
return this.
|
|
150
|
+
return this._entryIndex.length;
|
|
172
151
|
}
|
|
173
152
|
get canAppend() {
|
|
174
153
|
return this._canAppend;
|
|
@@ -179,36 +158,20 @@ let Log = Log_1 = class Log {
|
|
|
179
158
|
* @returns {boolean}
|
|
180
159
|
*/
|
|
181
160
|
has(cid) {
|
|
182
|
-
return this._entryIndex.
|
|
161
|
+
return this._entryIndex.has(cid);
|
|
183
162
|
}
|
|
184
163
|
/**
|
|
185
164
|
* Get all entries sorted. Don't use this method anywhere where performance matters
|
|
186
165
|
*/
|
|
187
|
-
toArray() {
|
|
166
|
+
async toArray() {
|
|
188
167
|
// we call init, because the values might be unitialized
|
|
189
|
-
return this.
|
|
168
|
+
return this.entryIndex.query([], this.sortFn.sort, true).all();
|
|
190
169
|
}
|
|
191
170
|
/**
|
|
192
171
|
* Returns the head index
|
|
193
172
|
*/
|
|
194
|
-
|
|
195
|
-
return this.
|
|
196
|
-
}
|
|
197
|
-
get memory() {
|
|
198
|
-
return this._memory;
|
|
199
|
-
}
|
|
200
|
-
async getHeads() {
|
|
201
|
-
const heads = new Array(this.headsIndex.index.size);
|
|
202
|
-
let i = 0;
|
|
203
|
-
for (const hash of this.headsIndex.index) {
|
|
204
|
-
heads[i++] = this._entryIndex.get(hash).then((x) => x?.init(this));
|
|
205
|
-
}
|
|
206
|
-
const resolved = await Promise.all(heads);
|
|
207
|
-
const defined = resolved.filter((x) => !!x);
|
|
208
|
-
if (defined.length !== resolved.length) {
|
|
209
|
-
logger.error("Failed to resolve all heads");
|
|
210
|
-
}
|
|
211
|
-
return defined;
|
|
173
|
+
getHeads(resolve = false) {
|
|
174
|
+
return this.entryIndex.getHeads(undefined, resolve);
|
|
212
175
|
}
|
|
213
176
|
/**
|
|
214
177
|
* Returns an array of Entry objects that reference entries which
|
|
@@ -238,9 +201,6 @@ let Log = Log_1 = class Log {
|
|
|
238
201
|
get blocks() {
|
|
239
202
|
return this._storage;
|
|
240
203
|
}
|
|
241
|
-
get nextsIndex() {
|
|
242
|
-
return this._nextsIndex;
|
|
243
|
-
}
|
|
244
204
|
get entryIndex() {
|
|
245
205
|
return this._entryIndex;
|
|
246
206
|
}
|
|
@@ -264,68 +224,89 @@ let Log = Log_1 = class Log {
|
|
|
264
224
|
this._identity = identity;
|
|
265
225
|
}
|
|
266
226
|
/**
|
|
267
|
-
*
|
|
227
|
+
* Get an entry.
|
|
268
228
|
* @param {string} [hash] The hashes of the entry
|
|
269
229
|
*/
|
|
270
230
|
get(hash, options) {
|
|
271
|
-
return this._entryIndex.get(hash, options);
|
|
231
|
+
return this._entryIndex.get(hash, options ? { type: "full", timeout: options.timeout } : undefined);
|
|
272
232
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
//
|
|
290
|
-
|
|
291
|
-
//
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
233
|
+
/**
|
|
234
|
+
* Get a entry with shallow representation
|
|
235
|
+
* @param {string} [hash] The hashes of the entry
|
|
236
|
+
*/
|
|
237
|
+
async getShallow(hash, options) {
|
|
238
|
+
return (await this._entryIndex.getShallow(hash))?.value;
|
|
239
|
+
}
|
|
240
|
+
/*
|
|
241
|
+
async traverse(
|
|
242
|
+
rootEntries: Entry<T>[],
|
|
243
|
+
amount = -1,
|
|
244
|
+
endHash?: string
|
|
245
|
+
): Promise<{ [key: string]: Entry<T> }> {
|
|
246
|
+
// Sort the given given root entries and use as the starting stack
|
|
247
|
+
let stack: Entry<T>[] = rootEntries.sort(this._sortFn).reverse();
|
|
248
|
+
|
|
249
|
+
// Cache for checking if we've processed an entry already
|
|
250
|
+
let traversed: { [key: string]: boolean } = {};
|
|
251
|
+
// End result
|
|
252
|
+
const result: { [key: string]: Entry<T> } = {};
|
|
253
|
+
let count = 0;
|
|
254
|
+
// Named function for getting an entry from the log
|
|
255
|
+
const getEntry = (e: string) => this.get(e);
|
|
256
|
+
|
|
257
|
+
// Add an entry to the stack and traversed nodes index
|
|
258
|
+
const addToStack = (entry: Entry<T>) => {
|
|
259
|
+
// If we've already processed the Entry<T>, don't add it to the stack
|
|
260
|
+
if (!entry || traversed[entry.hash]) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Add the entry in front of the stack and sort
|
|
265
|
+
stack = [entry, ...stack].sort(this._sortFn).reverse();
|
|
266
|
+
// Add to the cache of processed entries
|
|
267
|
+
traversed[entry.hash] = true;
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const addEntry = (rootEntry: Entry<T>) => {
|
|
271
|
+
result[rootEntry.hash] = rootEntry;
|
|
272
|
+
traversed[rootEntry.hash] = true;
|
|
273
|
+
count++;
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// Start traversal
|
|
277
|
+
// Process stack until it's empty (traversed the full log)
|
|
278
|
+
// or when we have the requested amount of entries
|
|
279
|
+
// If requested entry amount is -1, traverse all
|
|
280
|
+
while (stack.length > 0 && (count < amount || amount < 0)) {
|
|
281
|
+
// eslint-disable-line no-unmodified-loop-condition
|
|
282
|
+
// Get the next element from the stack
|
|
283
|
+
const entry = stack.shift();
|
|
284
|
+
if (!entry) {
|
|
285
|
+
throw new Error("Unexpected");
|
|
286
|
+
}
|
|
287
|
+
// Add to the result
|
|
288
|
+
addEntry(entry);
|
|
289
|
+
// If it is the specified end hash, break out of the while loop
|
|
290
|
+
if (endHash && endHash === entry.hash) break;
|
|
291
|
+
|
|
292
|
+
// Add entry's next references to the stack
|
|
293
|
+
const entries = (await Promise.all(entry.next.map(getEntry))).filter(
|
|
294
|
+
(x) => !!x
|
|
295
|
+
) as Entry<any>[];
|
|
296
|
+
entries.forEach(addToStack);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
stack = [];
|
|
300
|
+
traversed = {};
|
|
301
|
+
// End result
|
|
302
|
+
return result;
|
|
318
303
|
}
|
|
319
|
-
|
|
320
|
-
traversed = {};
|
|
321
|
-
// End result
|
|
322
|
-
return result;
|
|
323
|
-
}
|
|
304
|
+
*/
|
|
324
305
|
async getReferenceSamples(from, options) {
|
|
325
306
|
const hashes = new Set();
|
|
326
307
|
const pointerCount = options?.pointerCount || 0;
|
|
327
308
|
const memoryLimit = options?.memoryLimit;
|
|
328
|
-
const maxDistance = Math.min(pointerCount, this.
|
|
309
|
+
const maxDistance = Math.min(pointerCount, this.entryIndex.length);
|
|
329
310
|
if (maxDistance === 0) {
|
|
330
311
|
return [];
|
|
331
312
|
}
|
|
@@ -383,8 +364,9 @@ let Log = Log_1 = class Log {
|
|
|
383
364
|
}
|
|
384
365
|
/**
|
|
385
366
|
* Append an entry to the log.
|
|
386
|
-
* @param {
|
|
387
|
-
* @
|
|
367
|
+
* @param {T} data The data to be appended
|
|
368
|
+
* @param {AppendOptions} [options] The options for the append
|
|
369
|
+
* @returns {{ entry: Entry<T>; removed: ShallowEntry[] }} The appended entry and an array of removed entries
|
|
388
370
|
*/
|
|
389
371
|
async append(data, options = {}) {
|
|
390
372
|
// Update the clock (find the latest clock)
|
|
@@ -395,11 +377,14 @@ let Log = Log_1 = class Log {
|
|
|
395
377
|
}
|
|
396
378
|
}
|
|
397
379
|
await this.load({ reload: false });
|
|
398
|
-
const nexts = options.meta?.next ||
|
|
380
|
+
const nexts = options.meta?.next ||
|
|
381
|
+
(await this.entryIndex
|
|
382
|
+
.getHeads(undefined, { type: "shape", shape: Sorting.ENTRY_SORT_SHAPE })
|
|
383
|
+
.all());
|
|
399
384
|
// Calculate max time for log/graph
|
|
400
385
|
const clock = new Clock({
|
|
401
386
|
id: this._identity.publicKey.bytes,
|
|
402
|
-
timestamp: options?.meta?.timestamp || this._hlc.now()
|
|
387
|
+
timestamp: options?.meta?.timestamp || this._hlc.now(),
|
|
403
388
|
});
|
|
404
389
|
const entry = await Entry.create({
|
|
405
390
|
store: this._storage,
|
|
@@ -411,39 +396,47 @@ let Log = Log_1 = class Log {
|
|
|
411
396
|
type: options.meta?.type,
|
|
412
397
|
gidSeed: options.meta?.gidSeed,
|
|
413
398
|
data: options.meta?.data,
|
|
414
|
-
next: nexts
|
|
399
|
+
next: nexts,
|
|
415
400
|
},
|
|
416
401
|
encoding: this._encoding,
|
|
417
402
|
encryption: options.encryption
|
|
418
403
|
? {
|
|
419
404
|
keypair: options.encryption.keypair,
|
|
420
405
|
receiver: {
|
|
421
|
-
...options.encryption.receiver
|
|
422
|
-
}
|
|
406
|
+
...options.encryption.receiver,
|
|
407
|
+
},
|
|
423
408
|
}
|
|
424
409
|
: undefined,
|
|
425
|
-
canAppend: options.canAppend || this._canAppend
|
|
410
|
+
canAppend: options.canAppend || this._canAppend,
|
|
426
411
|
});
|
|
427
412
|
if (!entry.hash) {
|
|
428
413
|
throw new Error("Unexpected");
|
|
429
414
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
await this.
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
415
|
+
if (entry.meta.type !== EntryType.CUT) {
|
|
416
|
+
for (const e of nexts) {
|
|
417
|
+
if (!(await this.has(e.hash))) {
|
|
418
|
+
let entry;
|
|
419
|
+
if (e instanceof Entry) {
|
|
420
|
+
entry = e;
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
let resolved = await this.entryIndex.get(e.hash);
|
|
424
|
+
if (!resolved) {
|
|
425
|
+
// eslint-disable-next-line no-console
|
|
426
|
+
console.warn("Unexpected missing entry when joining", e.hash);
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
entry = resolved;
|
|
430
|
+
}
|
|
431
|
+
await this.join([entry]);
|
|
432
|
+
}
|
|
442
433
|
}
|
|
443
434
|
}
|
|
444
|
-
await this.
|
|
445
|
-
|
|
446
|
-
|
|
435
|
+
await this.entryIndex.put(entry, {
|
|
436
|
+
unique: true,
|
|
437
|
+
isHead: true,
|
|
438
|
+
toMultiHash: false,
|
|
439
|
+
});
|
|
447
440
|
const removed = await this.processEntry(entry);
|
|
448
441
|
entry.init({ encoding: this._encoding, keychain: this._keychain });
|
|
449
442
|
const trimmed = await this.trim(options?.trim);
|
|
@@ -454,22 +447,16 @@ let Log = Log_1 = class Log {
|
|
|
454
447
|
}
|
|
455
448
|
const changes = {
|
|
456
449
|
added: [entry],
|
|
457
|
-
removed
|
|
450
|
+
removed,
|
|
458
451
|
};
|
|
459
|
-
await this._headsIndex.updateHeadsCache(changes); // * here
|
|
460
452
|
await (options?.onChange || this._onChange)?.(changes);
|
|
461
453
|
return { entry, removed };
|
|
462
454
|
}
|
|
463
455
|
async reset(entries) {
|
|
464
|
-
|
|
465
|
-
this._entryIndex
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
cache: this._entryCache
|
|
469
|
-
});
|
|
470
|
-
await this.headsIndex.reset([]);
|
|
471
|
-
this._values = new Values(this._entryIndex, this._sortFn, []);
|
|
472
|
-
await this.join(entries);
|
|
456
|
+
const heads = await this.getHeads(true).all();
|
|
457
|
+
await this._entryIndex.clear();
|
|
458
|
+
await this._onChange?.({ added: [], removed: heads });
|
|
459
|
+
await this.join(entries || heads);
|
|
473
460
|
}
|
|
474
461
|
async remove(entry, options) {
|
|
475
462
|
await this.load({ reload: false });
|
|
@@ -477,269 +464,200 @@ let Log = Log_1 = class Log {
|
|
|
477
464
|
if (entries.length === 0) {
|
|
478
465
|
return {
|
|
479
466
|
added: [],
|
|
480
|
-
removed: []
|
|
467
|
+
removed: [],
|
|
481
468
|
};
|
|
482
469
|
}
|
|
470
|
+
const change = {
|
|
471
|
+
added: [],
|
|
472
|
+
removed: Array.isArray(entry) ? entry : [entry],
|
|
473
|
+
};
|
|
474
|
+
await this._onChange?.(change);
|
|
483
475
|
if (options?.recursively) {
|
|
484
476
|
await this.deleteRecursively(entry);
|
|
485
477
|
}
|
|
486
478
|
else {
|
|
487
479
|
for (const entry of entries) {
|
|
488
|
-
await this.delete(entry);
|
|
480
|
+
await this.delete(entry.hash);
|
|
489
481
|
}
|
|
490
482
|
}
|
|
491
|
-
const change = {
|
|
492
|
-
added: [],
|
|
493
|
-
removed: Array.isArray(entry) ? entry : [entry]
|
|
494
|
-
};
|
|
495
|
-
/* await Promise.all([
|
|
496
|
-
this._logCache?.queue(change),
|
|
497
|
-
this._onUpdate(change),
|
|
498
|
-
]); */
|
|
499
|
-
await this._onChange?.(change);
|
|
500
483
|
return change;
|
|
501
484
|
}
|
|
502
|
-
iterator(options
|
|
485
|
+
/* iterator(options?: {
|
|
486
|
+
from?: "tail" | "head";
|
|
487
|
+
amount?: number;
|
|
488
|
+
}): IterableIterator<string> {
|
|
503
489
|
const from = options?.from || "tail";
|
|
504
490
|
const amount = typeof options?.amount === "number" ? options?.amount : -1;
|
|
505
491
|
let next = from === "tail" ? this._values.tail : this._values.head;
|
|
506
|
-
const nextFn = from === "tail" ? (e) => e.prev : (e) => e.next;
|
|
492
|
+
const nextFn = from === "tail" ? (e: any) => e.prev : (e: any) => e.next;
|
|
507
493
|
return (function* () {
|
|
508
494
|
let counter = 0;
|
|
509
495
|
while (next) {
|
|
510
496
|
if (amount >= 0 && counter >= amount) {
|
|
511
497
|
return;
|
|
512
498
|
}
|
|
499
|
+
|
|
513
500
|
yield next.value;
|
|
514
501
|
counter++;
|
|
502
|
+
|
|
515
503
|
next = nextFn(next);
|
|
516
504
|
}
|
|
517
505
|
})();
|
|
518
|
-
}
|
|
506
|
+
} */
|
|
519
507
|
async trim(option = this._trim.options) {
|
|
520
508
|
return this._trim.trim(option);
|
|
521
509
|
}
|
|
522
|
-
/**
|
|
523
|
-
*
|
|
524
|
-
* @param entries
|
|
525
|
-
* @returns change
|
|
526
|
-
*/
|
|
527
|
-
/* async sync(
|
|
528
|
-
entries: (EntryWithRefs<T> | Entry<T> | string)[],
|
|
529
|
-
options: {
|
|
530
|
-
canAppend?: CanAppend<T>;
|
|
531
|
-
onChange?: (change: Change<T>) => void | Promise<void>;
|
|
532
|
-
timeout?: number;
|
|
533
|
-
} = {}
|
|
534
|
-
): Promise<void> {
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
logger.debug(`Sync request #${entries.length}`);
|
|
538
|
-
const entriesToJoin: (Entry<T> | string)[] = [];
|
|
539
|
-
for (const e of entries) {
|
|
540
|
-
if (e instanceof Entry || typeof e === "string") {
|
|
541
|
-
entriesToJoin.push(e);
|
|
542
|
-
} else {
|
|
543
|
-
for (const ref of e.references) {
|
|
544
|
-
entriesToJoin.push(ref);
|
|
545
|
-
}
|
|
546
|
-
entriesToJoin.push(e.entry);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
await this.join(entriesToJoin, {
|
|
551
|
-
canAppend: (entry) => {
|
|
552
|
-
const canAppend = options?.canAppend || this.canAppend;
|
|
553
|
-
return !canAppend || canAppend(entry);
|
|
554
|
-
},
|
|
555
|
-
onChange: (change) => {
|
|
556
|
-
options?.onChange?.(change);
|
|
557
|
-
return this._onChange?.({
|
|
558
|
-
added: change.added,
|
|
559
|
-
removed: change.removed,
|
|
560
|
-
});
|
|
561
|
-
},
|
|
562
|
-
timeout: options.timeout,
|
|
563
|
-
});
|
|
564
|
-
} */
|
|
565
510
|
async join(entriesOrLog, options) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
511
|
+
let entries;
|
|
512
|
+
let references = new Map();
|
|
513
|
+
if (entriesOrLog instanceof Log_1) {
|
|
514
|
+
if (entriesOrLog.entryIndex.length === 0)
|
|
515
|
+
return;
|
|
516
|
+
entries = await entriesOrLog.toArray();
|
|
517
|
+
for (const element of entries) {
|
|
518
|
+
references.set(element.hash, element);
|
|
570
519
|
}
|
|
571
|
-
};
|
|
572
|
-
await this.load({ reload: false });
|
|
573
|
-
if (entriesOrLog.length === 0) {
|
|
574
|
-
return;
|
|
575
520
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
const entriesBottomUp = [];
|
|
580
|
-
const stack = [];
|
|
581
|
-
const resolvedEntries = new Map();
|
|
582
|
-
const entries = Array.isArray(entriesOrLog)
|
|
583
|
-
? entriesOrLog
|
|
584
|
-
: await entriesOrLog.values.toArray();
|
|
585
|
-
// Build a list of already resolved entries, and filter out already joined entries
|
|
586
|
-
for (const e of entries) {
|
|
587
|
-
// TODO, do this less ugly
|
|
588
|
-
let hash;
|
|
589
|
-
if (e instanceof Entry) {
|
|
590
|
-
hash = e.hash;
|
|
591
|
-
resolvedEntries.set(e.hash, e);
|
|
592
|
-
if (this.has(hash)) {
|
|
593
|
-
continue;
|
|
594
|
-
}
|
|
595
|
-
stack.push(hash);
|
|
521
|
+
else if (Array.isArray(entriesOrLog)) {
|
|
522
|
+
if (entriesOrLog.length === 0) {
|
|
523
|
+
return;
|
|
596
524
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
if (
|
|
600
|
-
|
|
525
|
+
entries = [];
|
|
526
|
+
for (const element of entriesOrLog) {
|
|
527
|
+
if (element instanceof Entry) {
|
|
528
|
+
entries.push(element);
|
|
529
|
+
references.set(element.hash, element);
|
|
601
530
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
531
|
+
else if (typeof element === "string") {
|
|
532
|
+
let entry = await Entry.fromMultihash(this._storage, element, {
|
|
533
|
+
timeout: options?.timeout,
|
|
534
|
+
});
|
|
535
|
+
if (!entry) {
|
|
536
|
+
throw new Error("Missing entry in join by hash: " + element);
|
|
537
|
+
}
|
|
538
|
+
entries.push(entry);
|
|
539
|
+
}
|
|
540
|
+
else if (element instanceof ShallowEntry) {
|
|
541
|
+
let entry = await Entry.fromMultihash(this._storage, element.hash, {
|
|
542
|
+
timeout: options?.timeout,
|
|
543
|
+
});
|
|
544
|
+
if (!entry) {
|
|
545
|
+
throw new Error("Missing entry in join by hash: " + element.hash);
|
|
546
|
+
}
|
|
547
|
+
entries.push(entry);
|
|
609
548
|
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
549
|
+
else {
|
|
550
|
+
entries.push(element.entry);
|
|
551
|
+
references.set(element.entry.hash, element.entry);
|
|
552
|
+
for (const ref of element.references) {
|
|
553
|
+
references.set(ref.hash, ref);
|
|
615
554
|
}
|
|
616
|
-
stack.push(e2.hash);
|
|
617
555
|
}
|
|
618
556
|
}
|
|
619
557
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
if (
|
|
623
|
-
|
|
558
|
+
else {
|
|
559
|
+
let all = await entriesOrLog.all(); // TODO dont load all at once
|
|
560
|
+
if (all.length === 0) {
|
|
561
|
+
return;
|
|
624
562
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
resolvedEntries.set(entry.hash, entry);
|
|
632
|
-
let nexts;
|
|
633
|
-
if (entry.meta.type !== EntryType.CUT &&
|
|
634
|
-
(nexts = await entry.getNext())) {
|
|
635
|
-
let isRoot = true;
|
|
636
|
-
for (const next of nexts) {
|
|
637
|
-
if (!this.has(next)) {
|
|
638
|
-
isRoot = false;
|
|
639
|
-
}
|
|
640
|
-
else {
|
|
641
|
-
if (this._headsIndex.has(next)) {
|
|
642
|
-
const toRemove = (await this.get(next, options));
|
|
643
|
-
await this._headsIndex.del(toRemove);
|
|
644
|
-
removedHeads.push(toRemove);
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
let nextIndexSet = nextRefs.get(next);
|
|
648
|
-
if (!nextIndexSet) {
|
|
649
|
-
nextIndexSet = [];
|
|
650
|
-
nextIndexSet.push(entry);
|
|
651
|
-
nextRefs.set(next, nextIndexSet);
|
|
652
|
-
}
|
|
653
|
-
else {
|
|
654
|
-
nextIndexSet.push(entry);
|
|
655
|
-
}
|
|
656
|
-
if (!visited.has(next)) {
|
|
657
|
-
stack.push(next);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
if (isRoot) {
|
|
661
|
-
entriesBottomUp.push(entry);
|
|
662
|
-
}
|
|
563
|
+
entries = all;
|
|
564
|
+
}
|
|
565
|
+
let heads = new Map();
|
|
566
|
+
for (const entry of entries) {
|
|
567
|
+
if (heads.has(entry.hash)) {
|
|
568
|
+
continue;
|
|
663
569
|
}
|
|
664
|
-
|
|
665
|
-
|
|
570
|
+
heads.set(entry.hash, true);
|
|
571
|
+
for (const next of await entry.getNext()) {
|
|
572
|
+
heads.set(next, false);
|
|
666
573
|
}
|
|
667
574
|
}
|
|
668
|
-
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
575
|
+
for (const entry of entries) {
|
|
576
|
+
const p = this.joinRecursively(entry, {
|
|
577
|
+
references,
|
|
578
|
+
isHead: heads.get(entry.hash),
|
|
579
|
+
...options,
|
|
580
|
+
});
|
|
581
|
+
this._joining.set(entry.hash, p);
|
|
582
|
+
p.finally(() => {
|
|
583
|
+
this._joining.delete(entry.hash);
|
|
584
|
+
});
|
|
674
585
|
await p;
|
|
675
586
|
}
|
|
676
587
|
}
|
|
677
|
-
|
|
678
|
-
|
|
588
|
+
/**
|
|
589
|
+
* Bottom up join of entries into the log
|
|
590
|
+
* @param entry
|
|
591
|
+
* @param options
|
|
592
|
+
* @returns
|
|
593
|
+
*/
|
|
594
|
+
async joinRecursively(entry, options) {
|
|
595
|
+
if (this.entryIndex.length > (options?.length ?? Number.MAX_SAFE_INTEGER)) {
|
|
679
596
|
return;
|
|
680
597
|
}
|
|
681
|
-
if (!
|
|
598
|
+
if (!entry.hash) {
|
|
682
599
|
throw new Error("Unexpected");
|
|
683
600
|
}
|
|
684
|
-
|
|
601
|
+
if (await this.has(entry.hash)) {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
entry.init(this);
|
|
605
|
+
if (options?.verifySignatures) {
|
|
606
|
+
if (!(await entry.verifySignatures())) {
|
|
607
|
+
throw new Error('Invalid signature entry with hash "' + entry.hash + '"');
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
if (this?._canAppend && !(await this?._canAppend(entry))) {
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
const headsWithGid = await this.entryIndex
|
|
614
|
+
.getHeads(entry.gid, { type: "shape", shape: ENTRY_JOIN_SHAPE })
|
|
615
|
+
.all();
|
|
685
616
|
if (headsWithGid) {
|
|
686
|
-
for (const
|
|
687
|
-
|
|
617
|
+
for (const v of headsWithGid) {
|
|
618
|
+
// TODO second argument should be a time compare instead? what about next nexts?
|
|
619
|
+
// and check the cut entry is newer than the current 'entry'
|
|
620
|
+
if (v.meta.type === EntryType.CUT &&
|
|
621
|
+
v.meta.next.includes(entry.hash) &&
|
|
622
|
+
Sorting.compare(entry, v, this._sortFn) < 0) {
|
|
688
623
|
return; // already deleted
|
|
689
624
|
}
|
|
690
625
|
}
|
|
691
626
|
}
|
|
692
|
-
if (
|
|
693
|
-
|
|
694
|
-
if (!(await
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
// Update the internal entry index
|
|
702
|
-
await this._entryIndex.set(e);
|
|
703
|
-
await this._values.put(e);
|
|
704
|
-
if (e.meta.type !== EntryType.CUT) {
|
|
705
|
-
for (const a of e.next) {
|
|
706
|
-
if (!this.has(a)) {
|
|
707
|
-
await this.join([a]);
|
|
708
|
-
}
|
|
709
|
-
let nextIndexSet = this._nextsIndex.get(a);
|
|
710
|
-
if (!nextIndexSet) {
|
|
711
|
-
nextIndexSet = new Set();
|
|
712
|
-
nextIndexSet.add(e.hash);
|
|
713
|
-
this._nextsIndex.set(a, nextIndexSet);
|
|
714
|
-
}
|
|
715
|
-
else {
|
|
716
|
-
nextIndexSet.add(a);
|
|
627
|
+
if (entry.meta.type !== EntryType.CUT) {
|
|
628
|
+
for (const a of entry.next) {
|
|
629
|
+
if (!(await this.has(a))) {
|
|
630
|
+
const nested = options.references?.get(a) ||
|
|
631
|
+
(await Entry.fromMultihash(this._storage, a, {
|
|
632
|
+
timeout: options?.timeout,
|
|
633
|
+
}));
|
|
634
|
+
if (!nested) {
|
|
635
|
+
throw new Error("Missing entry in joinRecursively: " + a);
|
|
717
636
|
}
|
|
637
|
+
const p = this.joinRecursively(nested, options.isHead ? { ...options, isHead: false } : options);
|
|
638
|
+
this._joining.set(nested.hash, p);
|
|
639
|
+
p.finally(() => {
|
|
640
|
+
this._joining.delete(nested.hash);
|
|
641
|
+
});
|
|
642
|
+
await p;
|
|
718
643
|
}
|
|
719
644
|
}
|
|
720
|
-
const clock = await e.getClock();
|
|
721
|
-
this._hlc.update(clock.timestamp);
|
|
722
|
-
const removed = await this.processEntry(e);
|
|
723
|
-
const trimmed = await this.trim(options?.trim);
|
|
724
|
-
if (trimmed) {
|
|
725
|
-
for (const entry of trimmed) {
|
|
726
|
-
removed.push(entry);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
await this?._onChange?.({ added: [e], removed: removed });
|
|
730
645
|
}
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
646
|
+
const clock = await entry.getClock();
|
|
647
|
+
this._hlc.update(clock.timestamp);
|
|
648
|
+
await this._entryIndex.put(entry, {
|
|
649
|
+
unique: false,
|
|
650
|
+
isHead: options.isHead,
|
|
651
|
+
toMultiHash: true,
|
|
652
|
+
});
|
|
653
|
+
const removed = await this.processEntry(entry);
|
|
654
|
+
const trimmed = await this.trim(options?.trim);
|
|
655
|
+
if (trimmed) {
|
|
656
|
+
for (const entry of trimmed) {
|
|
657
|
+
removed.push(entry);
|
|
738
658
|
}
|
|
739
659
|
}
|
|
740
|
-
|
|
741
|
-
await this.headsIndex.put(e, options);
|
|
742
|
-
}
|
|
660
|
+
await this?._onChange?.({ added: [entry], removed: removed });
|
|
743
661
|
}
|
|
744
662
|
async processEntry(entry) {
|
|
745
663
|
if (entry.meta.type === EntryType.CUT) {
|
|
@@ -755,22 +673,25 @@ let Log = Log_1 = class Log {
|
|
|
755
673
|
const deleted = [];
|
|
756
674
|
while (stack.length > 0) {
|
|
757
675
|
const entry = stack.pop();
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
this.
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
for (const next of entry.next) {
|
|
769
|
-
const nextFromNext = this._nextsIndex.get(next);
|
|
770
|
-
if (nextFromNext) {
|
|
771
|
-
nextFromNext.delete(entry.hash);
|
|
676
|
+
const skip = counter === 0 && skipFirst;
|
|
677
|
+
if (!skip) {
|
|
678
|
+
const has = await this.has(entry.hash);
|
|
679
|
+
if (has) {
|
|
680
|
+
// TODO test last argument: It is for when multiple heads point to the same entry, hence we might visit it multiple times? or a concurrent delete process is doing it before us.
|
|
681
|
+
const deletedEntry = await this.delete(entry.hash);
|
|
682
|
+
if (deletedEntry) {
|
|
683
|
+
/* this._nextsIndex.delete(entry.hash); */
|
|
684
|
+
deleted.push(deletedEntry);
|
|
685
|
+
}
|
|
772
686
|
}
|
|
773
|
-
|
|
687
|
+
}
|
|
688
|
+
for (const next of entry.meta.next) {
|
|
689
|
+
const nextFromNext = this.entryIndex.getHasNext(next);
|
|
690
|
+
const entriesThatHasNext = await nextFromNext.all();
|
|
691
|
+
// if there are no entries which is not of "CUT" type, we can safely delete the next entry
|
|
692
|
+
// figureately speaking, these means where are cutting all branches to a stem, so we can delete the stem as well
|
|
693
|
+
let hasAlternativeNext = !!entriesThatHasNext.find((x) => x.meta.type !== EntryType.CUT);
|
|
694
|
+
if (!hasAlternativeNext) {
|
|
774
695
|
const ne = await this.get(next);
|
|
775
696
|
if (ne) {
|
|
776
697
|
stack.push(ne);
|
|
@@ -782,33 +703,10 @@ let Log = Log_1 = class Log {
|
|
|
782
703
|
await Promise.all(promises);
|
|
783
704
|
return deleted;
|
|
784
705
|
}
|
|
785
|
-
async delete(
|
|
786
|
-
this._trim.deleteFromCache(
|
|
787
|
-
await this.
|
|
788
|
-
|
|
789
|
-
update: false
|
|
790
|
-
}
|
|
791
|
-
}); // cache is not updated here, but at *
|
|
792
|
-
await this._values.delete(entry);
|
|
793
|
-
await this._entryIndex.delete(entry.hash);
|
|
794
|
-
this._nextsIndex.delete(entry.hash);
|
|
795
|
-
const newHeads = [];
|
|
796
|
-
for (const next of entry.next) {
|
|
797
|
-
const ne = await this.get(next);
|
|
798
|
-
if (ne) {
|
|
799
|
-
const nexts = this._nextsIndex.get(next);
|
|
800
|
-
nexts.delete(entry.hash);
|
|
801
|
-
if (nexts.size === 0) {
|
|
802
|
-
await this._headsIndex.put(ne);
|
|
803
|
-
newHeads.push(ne.hash);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
await this._headsIndex.updateHeadsCache({
|
|
808
|
-
added: newHeads,
|
|
809
|
-
removed: [entry.hash]
|
|
810
|
-
}); // * here
|
|
811
|
-
return entry.delete(this._storage);
|
|
706
|
+
async delete(hash) {
|
|
707
|
+
await this._trim.deleteFromCache(hash);
|
|
708
|
+
const removedEntry = await this._entryIndex.delete(hash);
|
|
709
|
+
return removedEntry;
|
|
812
710
|
}
|
|
813
711
|
/**
|
|
814
712
|
* Returns the log entries as a formatted string.
|
|
@@ -828,37 +726,29 @@ let Log = Log_1 = class Log {
|
|
|
828
726
|
let padding = new Array(Math.max(len - 1, 0));
|
|
829
727
|
padding = len > 1 ? padding.fill(" ") : padding;
|
|
830
728
|
padding = len > 0 ? padding.concat(["└─"]) : padding;
|
|
831
|
-
/* istanbul ignore next */
|
|
832
729
|
return (padding.join("") +
|
|
833
|
-
(payloadMapper
|
|
730
|
+
(payloadMapper?.(e.payload) || e.payload));
|
|
834
731
|
}))).join("\n");
|
|
835
732
|
}
|
|
836
|
-
async idle() {
|
|
837
|
-
await this._headsIndex.headsCache?.idle();
|
|
838
|
-
}
|
|
839
733
|
async close() {
|
|
840
734
|
// Don't return early here if closed = true, because "load" might create processes that needs to be closed
|
|
841
735
|
this._closed = true; // closed = true before doing below, else we might try to open the headsIndex cache because it is closed as we assume log is still open
|
|
842
|
-
|
|
843
|
-
await this.
|
|
844
|
-
|
|
845
|
-
this.
|
|
846
|
-
this._headsIndex = undefined;
|
|
847
|
-
this._memory = undefined;
|
|
848
|
-
this._values = undefined;
|
|
736
|
+
this._closeController.abort();
|
|
737
|
+
await this._indexer?.stop?.();
|
|
738
|
+
this._indexer = undefined;
|
|
739
|
+
this._loadedOnce = false;
|
|
849
740
|
}
|
|
850
741
|
async drop() {
|
|
851
742
|
// Don't return early here if closed = true, because "load" might create processes that needs to be closed
|
|
852
743
|
this._closed = true; // closed = true before doing below, else we might try to open the headsIndex cache because it is closed as we assume log is still open
|
|
853
|
-
|
|
854
|
-
await this.
|
|
855
|
-
await this.
|
|
856
|
-
await this.
|
|
857
|
-
await this._memory?.close();
|
|
744
|
+
this._closeController.abort();
|
|
745
|
+
await this.entryIndex?.clear();
|
|
746
|
+
await this._indexer?.drop();
|
|
747
|
+
await this._indexer?.stop?.();
|
|
858
748
|
}
|
|
859
749
|
async recover() {
|
|
860
750
|
// merge existing
|
|
861
|
-
const existing = await this.getHeads();
|
|
751
|
+
const existing = await this.getHeads(true).all();
|
|
862
752
|
const allHeads = new Map();
|
|
863
753
|
for (const head of existing) {
|
|
864
754
|
allHeads.set(head.hash, head);
|
|
@@ -887,42 +777,33 @@ let Log = Log_1 = class Log {
|
|
|
887
777
|
// assume they are valid, (let access control reject them if not)
|
|
888
778
|
await this.load({ reload: true, heads: [...allHeads.values()] });
|
|
889
779
|
}
|
|
890
|
-
async load(opts = {
|
|
780
|
+
async load(opts = {}) {
|
|
891
781
|
if (this.closed) {
|
|
892
782
|
throw new Error("Closed");
|
|
893
783
|
}
|
|
784
|
+
if (this._loadedOnce && !opts.reload && !opts.reset) {
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
this._loadedOnce = true;
|
|
894
788
|
const providedCustomHeads = Array.isArray(opts["heads"]);
|
|
895
789
|
const heads = providedCustomHeads
|
|
896
790
|
? opts["heads"]
|
|
897
|
-
: await this.
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
791
|
+
: await this._entryIndex
|
|
792
|
+
.getHeads(undefined, {
|
|
793
|
+
type: "full",
|
|
794
|
+
signal: this._closeController.signal,
|
|
901
795
|
ignoreMissing: opts.ignoreMissing,
|
|
902
|
-
|
|
903
|
-
})
|
|
796
|
+
timeout: opts.timeout,
|
|
797
|
+
})
|
|
798
|
+
.all();
|
|
904
799
|
if (heads) {
|
|
905
800
|
// Load the log
|
|
906
|
-
if (providedCustomHeads) {
|
|
801
|
+
if (providedCustomHeads || opts.reset) {
|
|
907
802
|
await this.reset(heads);
|
|
908
803
|
}
|
|
909
804
|
else {
|
|
910
|
-
/*
|
|
911
|
-
TODO feat amount load
|
|
912
|
-
const amount = (opts as { amount?: number }).amount;
|
|
913
|
-
if (amount != null && amount >= 0 && amount < heads.length) {
|
|
914
|
-
throw new Error(
|
|
915
|
-
"You are not loading all heads, this will lead to unexpected behaviours on write. Please load at least load: " +
|
|
916
|
-
amount +
|
|
917
|
-
" entries"
|
|
918
|
-
);
|
|
919
|
-
} */
|
|
920
805
|
await this.join(heads instanceof Entry ? [heads] : heads, {
|
|
921
|
-
/* length: amount, */
|
|
922
806
|
timeout: opts?.fetchEntryTimeout,
|
|
923
|
-
cache: {
|
|
924
|
-
update: false
|
|
925
|
-
}
|
|
926
807
|
});
|
|
927
808
|
}
|
|
928
809
|
}
|
|
@@ -933,7 +814,7 @@ let Log = Log_1 = class Log {
|
|
|
933
814
|
await log.join(!Array.isArray(entryOrHash) ? [entryOrHash] : entryOrHash, {
|
|
934
815
|
timeout: options.timeout,
|
|
935
816
|
trim: options.trim,
|
|
936
|
-
verifySignatures: true
|
|
817
|
+
verifySignatures: true,
|
|
937
818
|
});
|
|
938
819
|
return log;
|
|
939
820
|
}
|
|
@@ -943,7 +824,7 @@ let Log = Log_1 = class Log {
|
|
|
943
824
|
* Finds entries that are the heads of this collection,
|
|
944
825
|
* ie. entries that are not referenced by other entries.
|
|
945
826
|
*
|
|
946
|
-
* @param {Array<Entry<T>>} entries Entries to search heads from
|
|
827
|
+
* @param {Array<Entry<T>>} entries - Entries to search heads from
|
|
947
828
|
* @returns {Array<Entry<T>>}
|
|
948
829
|
*/
|
|
949
830
|
static findHeads(entries) {
|