@dxos/echo-pipeline 0.4.8-next.fff1521 → 0.4.9-main.1057b49
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/{chunk-3FVT6KX6.mjs → chunk-RTEEJ723.mjs} +289 -1807
- package/dist/lib/browser/chunk-RTEEJ723.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +633 -14
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +4 -332
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node/chunk-7VZVCCNF.cjs +1948 -0
- package/dist/lib/node/chunk-7VZVCCNF.cjs.map +7 -0
- package/dist/lib/node/index.cjs +643 -34
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +13 -338
- package/dist/lib/node/testing/index.cjs.map +4 -4
- package/dist/types/src/db-host/data-service.d.ts +3 -13
- package/dist/types/src/db-host/data-service.d.ts.map +1 -1
- package/dist/types/src/db-host/index.d.ts +0 -2
- package/dist/types/src/db-host/index.d.ts.map +1 -1
- package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
- package/dist/types/src/space/index.d.ts +0 -1
- package/dist/types/src/space/index.d.ts.map +1 -1
- package/dist/types/src/space/space-manager.d.ts +1 -4
- package/dist/types/src/space/space-manager.d.ts.map +1 -1
- package/dist/types/src/space/space.d.ts +1 -7
- package/dist/types/src/space/space.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +0 -2
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-agent-builder.d.ts +1 -3
- package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
- package/package.json +30 -33
- package/src/automerge/automerge-host.ts +1 -1
- package/src/db-host/data-service.ts +10 -56
- package/src/db-host/index.ts +0 -2
- package/src/space/control-pipeline.ts +3 -1
- package/src/space/index.ts +0 -1
- package/src/space/space-manager.ts +1 -13
- package/src/space/space.test.ts +2 -112
- package/src/space/space.ts +2 -60
- package/src/testing/index.ts +0 -2
- package/src/testing/test-agent-builder.ts +3 -8
- package/dist/lib/browser/chunk-3FVT6KX6.mjs.map +0 -7
- package/dist/lib/node/chunk-WZ4WTAN6.cjs +0 -3454
- package/dist/lib/node/chunk-WZ4WTAN6.cjs.map +0 -7
- package/dist/types/src/db-host/data-service-host.d.ts +0 -38
- package/dist/types/src/db-host/data-service-host.d.ts.map +0 -1
- package/dist/types/src/db-host/database-host.d.ts +0 -27
- package/dist/types/src/db-host/database-host.d.ts.map +0 -1
- package/dist/types/src/space/data-pipeline.d.ts +0 -80
- package/dist/types/src/space/data-pipeline.d.ts.map +0 -1
- package/dist/types/src/space/data-pipeline.test.d.ts +0 -1
- package/dist/types/src/space/data-pipeline.test.d.ts.map +0 -1
- package/dist/types/src/testing/database-test-rig.d.ts +0 -67
- package/dist/types/src/testing/database-test-rig.d.ts.map +0 -1
- package/dist/types/src/testing/util.d.ts +0 -14
- package/dist/types/src/testing/util.d.ts.map +0 -1
- package/dist/types/src/tests/database.test.d.ts +0 -2
- package/dist/types/src/tests/database.test.d.ts.map +0 -1
- package/src/db-host/data-service-host.ts +0 -233
- package/src/db-host/database-host.ts +0 -63
- package/src/space/data-pipeline.test.ts +0 -3
- package/src/space/data-pipeline.ts +0 -468
- package/src/testing/database-test-rig.ts +0 -289
- package/src/testing/util.ts +0 -85
- package/src/tests/database.test.ts +0 -100
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { Event } from '@dxos/async';
|
|
2
|
-
import { type CredentialProcessor, type FeedInfo, type SpecificCredential } from '@dxos/credentials';
|
|
3
|
-
import { ItemManager } from '@dxos/echo-db';
|
|
4
|
-
import { type PublicKey } from '@dxos/keys';
|
|
5
|
-
import { type ModelFactory } from '@dxos/model-factory';
|
|
6
|
-
import { type CreateEpochRequest } from '@dxos/protocols/proto/dxos/client/services';
|
|
7
|
-
import { type Credential, type Epoch } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
8
|
-
import { Timeframe } from '@dxos/timeframe';
|
|
9
|
-
import { DatabaseHost, type SnapshotManager } from '../db-host';
|
|
10
|
-
import { type MetadataStore } from '../metadata';
|
|
11
|
-
import { Pipeline } from '../pipeline';
|
|
12
|
-
export interface PipelineFactory {
|
|
13
|
-
openPipeline: (start: Timeframe) => Promise<Pipeline>;
|
|
14
|
-
}
|
|
15
|
-
export type DataPipelineParams = {
|
|
16
|
-
modelFactory: ModelFactory;
|
|
17
|
-
snapshotManager: SnapshotManager;
|
|
18
|
-
metadataStore: MetadataStore;
|
|
19
|
-
memberKey: PublicKey;
|
|
20
|
-
spaceKey: PublicKey;
|
|
21
|
-
feedInfoProvider: (feedKey: PublicKey) => FeedInfo | undefined;
|
|
22
|
-
snapshotId: string | undefined;
|
|
23
|
-
/**
|
|
24
|
-
* Called once.
|
|
25
|
-
*/
|
|
26
|
-
onPipelineCreated: (pipeline: Pipeline) => Promise<void>;
|
|
27
|
-
};
|
|
28
|
-
export type CreateEpochOptions = {
|
|
29
|
-
migration?: CreateEpochRequest.Migration;
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
|
-
* Controls data pipeline in the space.
|
|
33
|
-
* Consumes the pipeline and updates the database.
|
|
34
|
-
* Reacts to new epochs to restart the pipeline.
|
|
35
|
-
*/
|
|
36
|
-
export declare class DataPipeline implements CredentialProcessor {
|
|
37
|
-
private readonly _params;
|
|
38
|
-
private _ctx;
|
|
39
|
-
private _pipeline?;
|
|
40
|
-
private _targetTimeframe?;
|
|
41
|
-
private _lastAutomaticSnapshotTimeframe;
|
|
42
|
-
private _isOpen;
|
|
43
|
-
private _lastTimeframeSaveTime;
|
|
44
|
-
private _lastSnapshotSaveTime;
|
|
45
|
-
private _lastProcessedEpoch;
|
|
46
|
-
private _epochCtx?;
|
|
47
|
-
private _usage;
|
|
48
|
-
private _mutations;
|
|
49
|
-
databaseHost?: DatabaseHost;
|
|
50
|
-
itemManager: ItemManager;
|
|
51
|
-
/**
|
|
52
|
-
* Current epoch. Might be still processing.
|
|
53
|
-
*/
|
|
54
|
-
currentEpoch?: SpecificCredential<Epoch>;
|
|
55
|
-
/**
|
|
56
|
-
* Epoch currently applied.
|
|
57
|
-
*/
|
|
58
|
-
appliedEpoch?: SpecificCredential<Epoch>;
|
|
59
|
-
readonly onNewEpoch: Event<Credential>;
|
|
60
|
-
constructor(_params: DataPipelineParams);
|
|
61
|
-
get isOpen(): boolean;
|
|
62
|
-
get pipeline(): Pipeline | undefined;
|
|
63
|
-
get pipelineState(): import("../pipeline/pipeline").PipelineState | undefined;
|
|
64
|
-
setTargetTimeframe(timeframe: Timeframe): void;
|
|
65
|
-
processCredential(credential: Credential): Promise<void>;
|
|
66
|
-
open(): Promise<void>;
|
|
67
|
-
close(): Promise<void>;
|
|
68
|
-
private _consumePipeline;
|
|
69
|
-
private _createSnapshot;
|
|
70
|
-
private _saveTargetTimeframe;
|
|
71
|
-
private _saveCache;
|
|
72
|
-
private _noteTargetStateIfNeeded;
|
|
73
|
-
private _processEpochInSeparateTask;
|
|
74
|
-
private _processEpoch;
|
|
75
|
-
waitUntilTimeframe(timeframe: Timeframe): Promise<void>;
|
|
76
|
-
createEpoch(): Promise<Epoch>;
|
|
77
|
-
ensureEpochInitialized(): Promise<void>;
|
|
78
|
-
private _flush;
|
|
79
|
-
}
|
|
80
|
-
//# sourceMappingURL=data-pipeline.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"data-pipeline.d.ts","sourceRoot":"","sources":["../../../../src/space/data-pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//# sourceMappingURL=data-pipeline.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"data-pipeline.test.d.ts","sourceRoot":"","sources":["../../../../src/space/data-pipeline.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { DocumentModel } from '@dxos/document-model';
|
|
2
|
-
import { DatabaseProxy, ItemManager } from '@dxos/echo-db';
|
|
3
|
-
import { PublicKey } from '@dxos/keys';
|
|
4
|
-
import { ModelFactory } from '@dxos/model-factory';
|
|
5
|
-
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
6
|
-
import { type EchoSnapshot, type SpaceSnapshot } from '@dxos/protocols/proto/dxos/echo/snapshot';
|
|
7
|
-
import { TextModel } from '@dxos/text-model';
|
|
8
|
-
import { Timeframe } from '@dxos/timeframe';
|
|
9
|
-
import { ComplexMap } from '@dxos/util';
|
|
10
|
-
import { DatabaseHost } from '../db-host';
|
|
11
|
-
export declare class DatabaseTestBuilder {
|
|
12
|
-
readonly peers: ComplexMap<PublicKey, DatabaseTestPeer>;
|
|
13
|
-
createPeer(spaceKey?: PublicKey): Promise<DatabaseTestPeer>;
|
|
14
|
-
}
|
|
15
|
-
export declare class DatabaseTestPeer {
|
|
16
|
-
readonly rig: DatabaseTestBuilder;
|
|
17
|
-
readonly spaceKey: PublicKey;
|
|
18
|
-
readonly modelFactory: ModelFactory;
|
|
19
|
-
items: ItemManager;
|
|
20
|
-
proxy: DatabaseProxy;
|
|
21
|
-
host: DatabaseHost;
|
|
22
|
-
hostItems: ItemManager;
|
|
23
|
-
readonly key: PublicKey;
|
|
24
|
-
feedMessages: FeedMessage[];
|
|
25
|
-
readonly snapshots: Map<string, SpaceSnapshot>;
|
|
26
|
-
private currentEpoch?;
|
|
27
|
-
/**
|
|
28
|
-
* Sequence number of the last mutation confirmed to be written to the feed store.
|
|
29
|
-
*/
|
|
30
|
-
confirmed: number;
|
|
31
|
-
/**
|
|
32
|
-
* Current position of the peer's pipeline.
|
|
33
|
-
*/
|
|
34
|
-
timeframe: Timeframe;
|
|
35
|
-
snapshot: SpaceSnapshot | undefined;
|
|
36
|
-
private readonly _onConfirm;
|
|
37
|
-
private readonly _writes;
|
|
38
|
-
constructor(rig: DatabaseTestBuilder, spaceKey: PublicKey);
|
|
39
|
-
open(): Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
* Confirm mutations written to the local feed.
|
|
42
|
-
* @param seq Sequence number of the mutation to confirm. If not specified, all mutations will be confirmed.
|
|
43
|
-
*/
|
|
44
|
-
confirm(seq?: number): Promise<void>;
|
|
45
|
-
/**
|
|
46
|
-
* Replicate the database to the specified timeframe.
|
|
47
|
-
* @param to Timeframe to replicate to. If not specified, the database will be replicated to the latest timeframe (based on all other peers).
|
|
48
|
-
*/
|
|
49
|
-
replicate(to?: Timeframe): void;
|
|
50
|
-
/**
|
|
51
|
-
* Reload data from the feed. Wipes unconfirmed mutations.
|
|
52
|
-
*/
|
|
53
|
-
reload(): Promise<void>;
|
|
54
|
-
/**
|
|
55
|
-
* Create snapshot and use it for the next reload.
|
|
56
|
-
*/
|
|
57
|
-
makeSnapshot(): SpaceSnapshot;
|
|
58
|
-
createEpoch(mockSnapshot?: EchoSnapshot): void;
|
|
59
|
-
/**
|
|
60
|
-
* Gets all candidate messages according to the current timeframe.
|
|
61
|
-
* Does not take into account the current snapshot, timeframe dependencies, or the confirmed, or replicated state.
|
|
62
|
-
*/
|
|
63
|
-
private _getHeads;
|
|
64
|
-
private _processMessages;
|
|
65
|
-
getModel(id: string): DocumentModel | TextModel | undefined;
|
|
66
|
-
}
|
|
67
|
-
//# sourceMappingURL=database-test-rig.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"database-test-rig.d.ts","sourceRoot":"","sources":["../../../../src/testing/database-test-rig.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,WAAW,EAA4C,MAAM,eAAe,CAAC;AAGrG,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,0CAA0C,CAAC;AAEjG,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAwB,MAAM,YAAY,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI1C,qBAAa,mBAAmB;IAC9B,SAAgB,KAAK,0CAA+D;IAE9E,UAAU,CAAC,QAAQ,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAMlE;AAUD,qBAAa,gBAAgB;aAqCT,GAAG,EAAE,mBAAmB;aACxB,QAAQ,EAAE,SAAS;IArCrC,SAAgB,YAAY,eAA4E;IAEjG,KAAK,EAAG,WAAW,CAAC;IACpB,KAAK,EAAG,aAAa,CAAC;IAEtB,IAAI,EAAG,YAAY,CAAC;IACpB,SAAS,EAAG,WAAW,CAAC;IAM/B,SAAgB,GAAG,YAAsB;IAElC,YAAY,EAAE,WAAW,EAAE,CAAM;IAExC,SAAgB,SAAS,6BAAoC;IAC7D,OAAO,CAAC,YAAY,CAAC,CAAQ;IAE7B;;OAEG;IACI,SAAS,SAAM;IAEtB;;OAEG;IACI,SAAS,YAAmB;IAE5B,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC;IAE3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAE1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;gBAGjC,GAAG,EAAE,mBAAmB,EACxB,QAAQ,EAAE,SAAS;IAG/B,IAAI;IA6CV;;;OAGG;IACG,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM;IAe1B;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,EAAE,SAAS;IAUxB;;OAEG;IACG,MAAM;IAOZ;;OAEG;IACH,YAAY,IAAI,aAAa;IAS7B,WAAW,CAAC,YAAY,CAAC,EAAE,YAAY;IAqBvC;;;OAGG;IACH,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,gBAAgB;IAoCxB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,GAAG,SAAS;CA4B5D"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { DatabaseProxy, ItemManager } from '@dxos/echo-db';
|
|
2
|
-
import { ModelFactory } from '@dxos/model-factory';
|
|
3
|
-
import { DatabaseHost, type DataServiceHost } from '../db-host';
|
|
4
|
-
import { type DataPipeline } from '../space';
|
|
5
|
-
export declare const createMemoryDatabase: (modelFactory: ModelFactory) => Promise<{
|
|
6
|
-
backend: DatabaseHost;
|
|
7
|
-
itemManager: ItemManager;
|
|
8
|
-
}>;
|
|
9
|
-
export declare const createRemoteDatabaseFromDataServiceHost: (modelFactory: ModelFactory, dataServiceHost: DataServiceHost) => Promise<{
|
|
10
|
-
itemManager: ItemManager;
|
|
11
|
-
backend: DatabaseProxy;
|
|
12
|
-
}>;
|
|
13
|
-
export declare const testLocalDatabase: (create: DataPipeline, check?: DataPipeline) => Promise<void>;
|
|
14
|
-
//# sourceMappingURL=util.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../src/testing/util.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG3D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAMnD,OAAO,EAAE,YAAY,EAAE,KAAK,eAAe,EAA6C,MAAM,YAAY,CAAC;AAC3G,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,oBAAoB,iBAAwB,YAAY;;;EAuBpE,CAAC;AAEF,eAAO,MAAM,uCAAuC,iBACpC,YAAY,mBACT,eAAe;;;EAkBjC,CAAC;AAEF,eAAO,MAAM,iBAAiB,WAAkB,YAAY,UAAS,YAAY,kBAmBhF,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"database.test.d.ts","sourceRoot":"","sources":["../../../../src/tests/database.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2021 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { UpdateScheduler } from '@dxos/async';
|
|
6
|
-
import { Stream } from '@dxos/codec-protobuf';
|
|
7
|
-
import { Context } from '@dxos/context';
|
|
8
|
-
import { tagMutationsInBatch, type ItemDemuxer, type ItemManager, setMetadataOnObject } from '@dxos/echo-db';
|
|
9
|
-
import { type FeedWriter } from '@dxos/feed-store';
|
|
10
|
-
import { invariant } from '@dxos/invariant';
|
|
11
|
-
import { type PublicKey } from '@dxos/keys';
|
|
12
|
-
import { log } from '@dxos/log';
|
|
13
|
-
import { type DataMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
14
|
-
import { type EchoObject, type EchoObjectBatch } from '@dxos/protocols/proto/dxos/echo/object';
|
|
15
|
-
import {
|
|
16
|
-
EchoEvent,
|
|
17
|
-
type SyncRepoRequest,
|
|
18
|
-
type MutationReceipt,
|
|
19
|
-
type WriteRequest,
|
|
20
|
-
type SyncRepoResponse,
|
|
21
|
-
type HostInfo,
|
|
22
|
-
} from '@dxos/protocols/proto/dxos/echo/service';
|
|
23
|
-
import { ComplexMap } from '@dxos/util';
|
|
24
|
-
|
|
25
|
-
// After this limit the incremental object updates will be replaced with the full snapshot of the object.
|
|
26
|
-
const MUTATION_LIMIT_PER_OBJECT = 10;
|
|
27
|
-
|
|
28
|
-
export type DataServiceHostOptions = {
|
|
29
|
-
/**
|
|
30
|
-
* @default true
|
|
31
|
-
*/
|
|
32
|
-
deferEvents?: boolean;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Provides methods for DataService for a single space.
|
|
37
|
-
* A DataServiceRouter must be placed before it to route requests to different DataServiceHost instances based on space id.
|
|
38
|
-
*/
|
|
39
|
-
// TODO(burdon): Move to client-services.
|
|
40
|
-
export class DataServiceHost {
|
|
41
|
-
private readonly _ctx = new Context();
|
|
42
|
-
|
|
43
|
-
private readonly _clientTagMap = new ComplexMap<[feedKey: PublicKey, seq: number], string>(
|
|
44
|
-
([feedKey, seq]) => `${feedKey.toHex()}:${seq}`,
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
constructor(
|
|
48
|
-
private readonly _itemManager: ItemManager,
|
|
49
|
-
private readonly _itemDemuxer: ItemDemuxer,
|
|
50
|
-
private readonly _flush: () => Promise<void>,
|
|
51
|
-
private readonly _writeStream: FeedWriter<DataMessage> | undefined,
|
|
52
|
-
private readonly _opts: DataServiceHostOptions = {},
|
|
53
|
-
) {}
|
|
54
|
-
|
|
55
|
-
async open() {}
|
|
56
|
-
|
|
57
|
-
async close() {
|
|
58
|
-
await this._ctx.dispose();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private get _deferEvents(): boolean {
|
|
62
|
-
return this._opts.deferEvents ?? true;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Real-time subscription to data objects in a space.
|
|
67
|
-
*/
|
|
68
|
-
subscribe(): Stream<EchoEvent> {
|
|
69
|
-
return new Stream(({ next, close, ctx }) => {
|
|
70
|
-
// This looks ridiculous..
|
|
71
|
-
ctx.onDispose(this._ctx.onDispose(close));
|
|
72
|
-
|
|
73
|
-
// send current state
|
|
74
|
-
const objects = Array.from(this._itemManager.entities.values()).map((entity) => entity.createSnapshot());
|
|
75
|
-
next({
|
|
76
|
-
batch: {
|
|
77
|
-
objects,
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const updateScheduler = new UpdateScheduler(
|
|
82
|
-
ctx,
|
|
83
|
-
async () => {
|
|
84
|
-
flushPendingUpdate();
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
maxFrequency: 10,
|
|
88
|
-
},
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
const pendingUpdates: EchoObject[] = [];
|
|
92
|
-
const mutationsPerObject = new Map<string, number>();
|
|
93
|
-
|
|
94
|
-
const clearPendingUpdates = () => {
|
|
95
|
-
pendingUpdates.length = 0;
|
|
96
|
-
mutationsPerObject.clear();
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const flushPendingUpdate = () => {
|
|
100
|
-
const stagedEvents: EchoObject[] = [];
|
|
101
|
-
const objectsWithSnapshots = new Set<string>();
|
|
102
|
-
for (const [id, count] of mutationsPerObject) {
|
|
103
|
-
if (count >= MUTATION_LIMIT_PER_OBJECT) {
|
|
104
|
-
objectsWithSnapshots.add(id);
|
|
105
|
-
const entity = this._itemManager.entities.get(id);
|
|
106
|
-
if (entity) {
|
|
107
|
-
stagedEvents.push(entity.createSnapshot());
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
for (const obj of pendingUpdates) {
|
|
113
|
-
if (!objectsWithSnapshots.has(obj.objectId)) {
|
|
114
|
-
stagedEvents.push(obj);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
next({
|
|
119
|
-
batch: {
|
|
120
|
-
objects: stagedEvents,
|
|
121
|
-
},
|
|
122
|
-
});
|
|
123
|
-
clearPendingUpdates();
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
// Subscribe to clear events on Epoch processing.
|
|
127
|
-
this._itemDemuxer.snapshot.on(ctx, (snapshot) => {
|
|
128
|
-
clearPendingUpdates();
|
|
129
|
-
next({
|
|
130
|
-
action: EchoEvent.DatabaseAction.RESET,
|
|
131
|
-
batch: { objects: snapshot.items },
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// Subscribe to mutations.
|
|
136
|
-
this._itemDemuxer.mutation.on(ctx, (message) => {
|
|
137
|
-
const { batch, meta } = message;
|
|
138
|
-
invariant(!(meta as any).clientTag, 'Unexpected client tag in mutation message');
|
|
139
|
-
log('message', { batch: batch.objects?.length, meta });
|
|
140
|
-
|
|
141
|
-
const clientTag = this._clientTagMap.get([message.meta.feedKey, message.meta.seq]);
|
|
142
|
-
// TODO(dmaretskyi): Memory leak with _clientTagMap not getting cleared.
|
|
143
|
-
|
|
144
|
-
// Assign feed metadata
|
|
145
|
-
batch.objects?.forEach((object) => {
|
|
146
|
-
setMetadataOnObject(object, { ...meta });
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// Assign client tag metadata
|
|
150
|
-
if (clientTag) {
|
|
151
|
-
flushPendingUpdate();
|
|
152
|
-
|
|
153
|
-
tagMutationsInBatch(batch, clientTag, 0);
|
|
154
|
-
|
|
155
|
-
next({
|
|
156
|
-
clientTag,
|
|
157
|
-
feedKey: message.meta.feedKey,
|
|
158
|
-
seq: message.meta.seq,
|
|
159
|
-
batch,
|
|
160
|
-
});
|
|
161
|
-
} else {
|
|
162
|
-
for (const obj of batch.objects ?? []) {
|
|
163
|
-
const newCount = (mutationsPerObject.get(obj.objectId) ?? 0) + 1;
|
|
164
|
-
mutationsPerObject.set(obj.objectId, newCount);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
for (const obj of batch.objects ?? []) {
|
|
168
|
-
if ((mutationsPerObject.get(obj.objectId) ?? 0) < MUTATION_LIMIT_PER_OBJECT) {
|
|
169
|
-
pendingUpdates.push(obj);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (this._deferEvents) {
|
|
174
|
-
updateScheduler.trigger();
|
|
175
|
-
} else {
|
|
176
|
-
flushPendingUpdate();
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async write(request: WriteRequest): Promise<MutationReceipt> {
|
|
184
|
-
invariant(!this._ctx.disposed, 'Cannot write to closed DataServiceHost');
|
|
185
|
-
invariant(this._writeStream, 'Cannot write mutations in readonly mode');
|
|
186
|
-
|
|
187
|
-
log('write', { clientTag: request.clientTag, objectCount: request.batch.objects?.length ?? 0 });
|
|
188
|
-
|
|
189
|
-
// Clear client metadata.
|
|
190
|
-
const message = createDataMessage(request.batch);
|
|
191
|
-
|
|
192
|
-
const receipt = await this._writeStream.write(message, {
|
|
193
|
-
afterWrite: async (receipt) => {
|
|
194
|
-
// Runs before the mutation is read from the pipeline.
|
|
195
|
-
if (request.clientTag) {
|
|
196
|
-
log('tag', { clientTag: request.clientTag, feedKey: receipt.feedKey, seq: receipt.seq });
|
|
197
|
-
this._clientTagMap.set([receipt.feedKey, receipt.seq], request.clientTag);
|
|
198
|
-
}
|
|
199
|
-
},
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
return receipt;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async flush(): Promise<void> {
|
|
206
|
-
await this._flush();
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
getHostInfo(): Promise<HostInfo> {
|
|
210
|
-
throw new Error('Method not implemented.');
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
syncRepo(request: SyncRepoRequest): Stream<SyncRepoResponse> {
|
|
214
|
-
throw new Error('Method not implemented.');
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
sendSyncMessage(request: SyncRepoRequest): Promise<void> {
|
|
218
|
-
throw new Error('Method not implemented.');
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const createDataMessage = (batch: EchoObjectBatch) => ({
|
|
223
|
-
batch: {
|
|
224
|
-
objects: batch.objects?.map((object) => ({
|
|
225
|
-
...object,
|
|
226
|
-
mutations: object.mutations?.map((mutation) => ({
|
|
227
|
-
...mutation,
|
|
228
|
-
meta: undefined,
|
|
229
|
-
})),
|
|
230
|
-
meta: undefined,
|
|
231
|
-
})),
|
|
232
|
-
},
|
|
233
|
-
});
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2023 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { type EchoProcessor, ItemDemuxer, type ItemManager } from '@dxos/echo-db';
|
|
6
|
-
import { type FeedWriter } from '@dxos/feed-store';
|
|
7
|
-
import { type ModelFactory } from '@dxos/model-factory';
|
|
8
|
-
import { type DataMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
9
|
-
import { type EchoSnapshot } from '@dxos/protocols/proto/dxos/echo/snapshot';
|
|
10
|
-
|
|
11
|
-
import { DataServiceHost, type DataServiceHostOptions } from './data-service-host';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Database backend that operates on two streams: read and write.
|
|
15
|
-
* Mutations are read from the incoming streams and applied to the ItemManager via ItemDemuxer.
|
|
16
|
-
* Write operations result in mutations being written to the outgoing stream.
|
|
17
|
-
*/
|
|
18
|
-
export class DatabaseHost {
|
|
19
|
-
private _echoProcessor!: EchoProcessor;
|
|
20
|
-
private _itemManager!: ItemManager;
|
|
21
|
-
public _itemDemuxer!: ItemDemuxer;
|
|
22
|
-
|
|
23
|
-
constructor(
|
|
24
|
-
private readonly _outboundStream: FeedWriter<DataMessage> | undefined,
|
|
25
|
-
private readonly _flush: () => Promise<void>,
|
|
26
|
-
) {}
|
|
27
|
-
|
|
28
|
-
get isReadOnly(): boolean {
|
|
29
|
-
return !!this._outboundStream;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get echoProcessor() {
|
|
33
|
-
return this._echoProcessor;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async open(itemManager: ItemManager, modelFactory: ModelFactory) {
|
|
37
|
-
this._itemManager = itemManager;
|
|
38
|
-
this._itemManager._debugLabel = 'host';
|
|
39
|
-
|
|
40
|
-
this._itemDemuxer = new ItemDemuxer(itemManager, modelFactory);
|
|
41
|
-
this._echoProcessor = this._itemDemuxer.open();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async close() {}
|
|
45
|
-
|
|
46
|
-
getWriteStream(): FeedWriter<DataMessage> | undefined {
|
|
47
|
-
return this._outboundStream;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
createSnapshot(): EchoSnapshot {
|
|
51
|
-
return this._itemDemuxer.createSnapshot();
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
createDataServiceHost(opts: DataServiceHostOptions = {}) {
|
|
55
|
-
return new DataServiceHost(
|
|
56
|
-
this._itemManager,
|
|
57
|
-
this._itemDemuxer,
|
|
58
|
-
this._flush,
|
|
59
|
-
this._outboundStream ?? undefined,
|
|
60
|
-
opts,
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
}
|