@fluid-experimental/property-dds 2.0.0-dev.5.2.0.169897 → 2.0.0-dev.6.4.0.191258
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/.mocharc.js +12 -0
- package/CHANGELOG.md +36 -0
- package/dist/propertyTree.d.ts +2 -0
- package/dist/propertyTree.d.ts.map +1 -1
- package/dist/propertyTree.js +74 -21
- package/dist/propertyTree.js.map +1 -1
- package/dist/propertyTreeExtFactories.js +3 -3
- package/dist/propertyTreeExtFactories.js.map +1 -1
- package/lib/propertyTree.d.ts +2 -0
- package/lib/propertyTree.d.ts.map +1 -1
- package/lib/propertyTree.js +70 -17
- package/lib/propertyTree.js.map +1 -1
- package/lib/propertyTreeExtFactories.js +1 -1
- package/lib/propertyTreeExtFactories.js.map +1 -1
- package/package.json +29 -30
- package/src/propertyTree.ts +67 -14
- package/src/propertyTreeExtFactories.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluid-experimental/property-dds",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.6.4.0.191258",
|
|
4
4
|
"description": "definition of the property distributed data store",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -15,16 +15,16 @@
|
|
|
15
15
|
"module": "lib/index.js",
|
|
16
16
|
"types": "dist/index.d.ts",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@fluid-experimental/property-changeset": "2.0.0-dev.
|
|
19
|
-
"@fluid-experimental/property-properties": "2.0.0-dev.
|
|
20
|
-
"@
|
|
21
|
-
"@fluidframework/container-definitions": "2.0.0-dev.
|
|
22
|
-
"@fluidframework/core-interfaces": "2.0.0-dev.
|
|
23
|
-
"@fluidframework/datastore-definitions": "2.0.0-dev.
|
|
18
|
+
"@fluid-experimental/property-changeset": "2.0.0-dev.6.4.0.191258",
|
|
19
|
+
"@fluid-experimental/property-properties": "2.0.0-dev.6.4.0.191258",
|
|
20
|
+
"@fluid-internal/client-utils": "2.0.0-dev.6.4.0.191258",
|
|
21
|
+
"@fluidframework/container-definitions": "2.0.0-dev.6.4.0.191258",
|
|
22
|
+
"@fluidframework/core-interfaces": "2.0.0-dev.6.4.0.191258",
|
|
23
|
+
"@fluidframework/datastore-definitions": "2.0.0-dev.6.4.0.191258",
|
|
24
24
|
"@fluidframework/protocol-definitions": "^1.1.0",
|
|
25
|
-
"@fluidframework/runtime-definitions": "2.0.0-dev.
|
|
26
|
-
"@fluidframework/runtime-utils": "2.0.0-dev.
|
|
27
|
-
"@fluidframework/shared-object-base": "2.0.0-dev.
|
|
25
|
+
"@fluidframework/runtime-definitions": "2.0.0-dev.6.4.0.191258",
|
|
26
|
+
"@fluidframework/runtime-utils": "2.0.0-dev.6.4.0.191258",
|
|
27
|
+
"@fluidframework/shared-object-base": "2.0.0-dev.6.4.0.191258",
|
|
28
28
|
"axios": "^0.26.0",
|
|
29
29
|
"buffer": "^6.0.3",
|
|
30
30
|
"fastest-json-copy": "^1.0.1",
|
|
@@ -32,27 +32,27 @@
|
|
|
32
32
|
"lz4js": "^0.2.0",
|
|
33
33
|
"msgpackr": "^1.4.7",
|
|
34
34
|
"pako": "^2.0.4",
|
|
35
|
-
"uuid": "^
|
|
35
|
+
"uuid": "^9.0.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@fluid-experimental/property-common": "2.0.0-dev.
|
|
39
|
-
"@fluid-internal/test-drivers": "2.0.0-dev.
|
|
40
|
-
"@fluidframework/build-common": "^
|
|
41
|
-
"@fluidframework/
|
|
42
|
-
"@fluidframework/
|
|
43
|
-
"@fluidframework/
|
|
44
|
-
"@fluidframework/
|
|
45
|
-
"@fluidframework/
|
|
46
|
-
"@fluidframework/
|
|
47
|
-
"@fluidframework/
|
|
48
|
-
"@fluidframework/
|
|
49
|
-
"@fluidframework/test-utils": "2.0.0-dev.
|
|
38
|
+
"@fluid-experimental/property-common": "2.0.0-dev.6.4.0.191258",
|
|
39
|
+
"@fluid-internal/test-drivers": "2.0.0-dev.6.4.0.191258",
|
|
40
|
+
"@fluidframework/build-common": "^2.0.0",
|
|
41
|
+
"@fluidframework/build-tools": "^0.22.0",
|
|
42
|
+
"@fluidframework/container-loader": "2.0.0-dev.6.4.0.191258",
|
|
43
|
+
"@fluidframework/driver-definitions": "2.0.0-dev.6.4.0.191258",
|
|
44
|
+
"@fluidframework/eslint-config-fluid": "^2.1.0",
|
|
45
|
+
"@fluidframework/local-driver": "2.0.0-dev.6.4.0.191258",
|
|
46
|
+
"@fluidframework/mocha-test-setup": "2.0.0-dev.6.4.0.191258",
|
|
47
|
+
"@fluidframework/sequence": "2.0.0-dev.6.4.0.191258",
|
|
48
|
+
"@fluidframework/server-local-server": "^1.0.1",
|
|
49
|
+
"@fluidframework/test-runtime-utils": "2.0.0-dev.6.4.0.191258",
|
|
50
|
+
"@fluidframework/test-utils": "2.0.0-dev.6.4.0.191258",
|
|
50
51
|
"@microsoft/api-extractor": "^7.34.4",
|
|
51
52
|
"@types/lodash": "^4.14.118",
|
|
52
53
|
"@types/mocha": "^9.1.1",
|
|
53
|
-
"@types/node": "^
|
|
54
|
+
"@types/node": "^16.18.38",
|
|
54
55
|
"chai": "^4.2.0",
|
|
55
|
-
"concurrently": "^7.6.0",
|
|
56
56
|
"copyfiles": "^2.4.1",
|
|
57
57
|
"cross-env": "^7.0.3",
|
|
58
58
|
"easy-table": "^1.1.1",
|
|
@@ -62,7 +62,6 @@
|
|
|
62
62
|
"mocha-json-output-reporter": "^2.0.1",
|
|
63
63
|
"mocha-multi-reporters": "^1.5.1",
|
|
64
64
|
"moment": "^2.21.0",
|
|
65
|
-
"nyc": "^15.1.0",
|
|
66
65
|
"prettier": "~2.6.2",
|
|
67
66
|
"rimraf": "^4.4.0",
|
|
68
67
|
"typescript": "~4.5.5"
|
|
@@ -78,7 +77,7 @@
|
|
|
78
77
|
"build:esnext": "tsc --project ./tsconfig.esnext.json",
|
|
79
78
|
"build:test": "tsc --project ./src/test/tsconfig.json",
|
|
80
79
|
"ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../../_api-extractor-temp/",
|
|
81
|
-
"clean": "rimraf dist lib *.tsbuildinfo *.build.log",
|
|
80
|
+
"clean": "rimraf --glob 'dist' 'lib' '*.tsbuildinfo' '*.build.log' '_api-extractor-temp' 'nyc'",
|
|
82
81
|
"eslint": "eslint src",
|
|
83
82
|
"eslint:fix": "eslint src --fix",
|
|
84
83
|
"format": "npm run prettier:fix",
|
|
@@ -87,9 +86,9 @@
|
|
|
87
86
|
"prettier": "prettier --check . --ignore-path ../../../../.prettierignore",
|
|
88
87
|
"prettier:fix": "prettier --write . --ignore-path ../../../../.prettierignore",
|
|
89
88
|
"test": "npm run test:mocha",
|
|
90
|
-
"test:mocha": "mocha \"dist/**/*.spec.js\" --exit -r node_modules/@fluidframework/mocha-test-setup
|
|
91
|
-
"test:mocha-ts": "cross-env FLUID_TEST_VERBOSE=1 TS_NODE_PROJECT=\"./src/test/tsconfig.json\" mocha --require ts-node/register --extensions ts,tsx \"src/test/**/*.spec.ts\" --exit -r node_modules/@fluidframework/mocha-test-setup --
|
|
92
|
-
"test:mocha
|
|
89
|
+
"test:mocha": "mocha \"dist/**/*.spec.js\" --exit -r node_modules/@fluidframework/mocha-test-setup",
|
|
90
|
+
"test:mocha-ts": "cross-env FLUID_TEST_VERBOSE=1 TS_NODE_PROJECT=\"./src/test/tsconfig.json\" mocha --require ts-node/register --extensions ts,tsx \"src/test/**/*.spec.ts\" --exit -r node_modules/@fluidframework/mocha-test-setup --timeout 1500000",
|
|
91
|
+
"test:mocha-ts-inspect": "cross-env FLUID_TEST_VERBOSE=1 TS_NODE_PROJECT=\"./src/test/tsconfig.json\" mocha --inspect-brk --require ts-node/register --extensions ts,tsx \"src/test/**/*.spec.ts\" --exit -r node_modules/@fluidframework/mocha-test-setup --timeout 1500000",
|
|
93
92
|
"test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
|
|
94
93
|
"tsc": "tsc"
|
|
95
94
|
}
|
package/src/propertyTree.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
/* eslint-disable import/no-internal-modules */
|
|
7
7
|
import isEmpty from "lodash/isEmpty";
|
|
8
8
|
import findIndex from "lodash/findIndex";
|
|
9
|
+
import find from "lodash/find";
|
|
10
|
+
import isEqual from "lodash/isEqual";
|
|
9
11
|
import range from "lodash/range";
|
|
10
12
|
import { copy as cloneDeep } from "fastest-json-copy";
|
|
11
13
|
import { Packr } from "msgpackr";
|
|
@@ -19,7 +21,7 @@ import {
|
|
|
19
21
|
IChannelFactory,
|
|
20
22
|
} from "@fluidframework/datastore-definitions";
|
|
21
23
|
|
|
22
|
-
import { bufferToString, stringToBuffer } from "@
|
|
24
|
+
import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
|
|
23
25
|
import { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
|
|
24
26
|
import { IFluidSerializer, SharedObject } from "@fluidframework/shared-object-base";
|
|
25
27
|
import { SummaryTreeBuilder } from "@fluidframework/runtime-utils";
|
|
@@ -84,6 +86,7 @@ export interface SharedPropertyTreeOptions {
|
|
|
84
86
|
paths?: string[];
|
|
85
87
|
clientFiltering?: boolean;
|
|
86
88
|
useMH?: boolean;
|
|
89
|
+
disablePartialCheckout?: boolean;
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
export interface ISharedPropertyTreeEncDec {
|
|
@@ -195,12 +198,14 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
195
198
|
private scopeFutureDeltasToPaths(paths?: string[]) {
|
|
196
199
|
// Backdoor to emit "partial_checkout" events on the socket. The delta manager at container runtime layer is
|
|
197
200
|
// a proxy and the delta manager at the container context layer is yet another proxy, so account for that.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
+
if (!this.options.disablePartialCheckout) {
|
|
202
|
+
let dm = (this.runtime.deltaManager as any).deltaManager;
|
|
203
|
+
if (dm.deltaManager !== undefined) {
|
|
204
|
+
dm = dm.deltaManager;
|
|
205
|
+
}
|
|
206
|
+
const socket = dm.connectionManager.connection.socket;
|
|
207
|
+
socket.emit("partial_checkout", { paths });
|
|
201
208
|
}
|
|
202
|
-
const socket = dm.connectionManager.connection.socket;
|
|
203
|
-
socket.emit("partial_checkout", { paths });
|
|
204
209
|
}
|
|
205
210
|
|
|
206
211
|
public _reportDirtinessToView() {
|
|
@@ -678,6 +683,7 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
678
683
|
const lastDelta = commitMetadata.sequenceNumber;
|
|
679
684
|
|
|
680
685
|
const dm = (this.runtime.deltaManager as any).deltaManager;
|
|
686
|
+
// TODO: This is accessing a private member of the delta manager, and should not be.
|
|
681
687
|
await dm.getDeltas(
|
|
682
688
|
"DocumentOpen",
|
|
683
689
|
firstDelta,
|
|
@@ -690,8 +696,11 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
690
696
|
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
691
697
|
for (let i = 0; i < missingDeltas.length; i++) {
|
|
692
698
|
if (missingDeltas[i].sequenceNumber < commitMetadata.sequenceNumber) {
|
|
699
|
+
// TODO: Don't spy on the DeltaManager's private internals.
|
|
700
|
+
// This is trying to mimic what DeltaManager does in processInboundMessage, but there's no guarantee that
|
|
701
|
+
// private implementation won't change.
|
|
693
702
|
const remoteChange: IPropertyTreeMessage = JSON.parse(
|
|
694
|
-
missingDeltas[i].contents,
|
|
703
|
+
missingDeltas[i].contents as string,
|
|
695
704
|
).contents.contents.content.contents;
|
|
696
705
|
const { changeSet } = (
|
|
697
706
|
await axios.get(
|
|
@@ -791,6 +800,10 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
791
800
|
|
|
792
801
|
getRebasedChanges(startGuid: string, endGuid?: string) {
|
|
793
802
|
const startIndex = findIndex(this.remoteChanges, (c) => c.guid === startGuid);
|
|
803
|
+
if (startIndex === -1 && startGuid !== "") {
|
|
804
|
+
// TODO: Consider throwing an error once clients have picked up PR #16277.
|
|
805
|
+
console.error("Unknown start GUID specified.");
|
|
806
|
+
}
|
|
794
807
|
if (endGuid !== undefined) {
|
|
795
808
|
const endIndex = findIndex(this.remoteChanges, (c) => c.guid === endGuid);
|
|
796
809
|
return this.remoteChanges.slice(startIndex + 1, endIndex + 1);
|
|
@@ -803,7 +816,7 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
803
816
|
pendingChanges: SerializedChangeSet,
|
|
804
817
|
newTipDelta: SerializedChangeSet,
|
|
805
818
|
): boolean {
|
|
806
|
-
let rebaseBaseChangeSet
|
|
819
|
+
let rebaseBaseChangeSet;
|
|
807
820
|
|
|
808
821
|
const accumulatedChanges: SerializedChangeSet = {};
|
|
809
822
|
const conflicts = [] as any[];
|
|
@@ -813,15 +826,29 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
813
826
|
// assert(JSON.stringify(this.localChanges[0].changeSet) === JSON.stringify(change.changeSet),
|
|
814
827
|
// "Local change different than rebased remote change.");
|
|
815
828
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
829
|
+
if (isEqual(this.localChanges[0].changeSet, change.changeSet)) {
|
|
830
|
+
// If we got a confirmation of the commit on the tip of the localChanges array,
|
|
831
|
+
// there will be no update of the tip view at all. We just move it from local changes
|
|
832
|
+
// to remote changes
|
|
833
|
+
this.localChanges.shift();
|
|
820
834
|
|
|
821
|
-
|
|
835
|
+
return false;
|
|
836
|
+
} else {
|
|
837
|
+
// There is a case where the localChanges that were created by incrementally rebasing with respect
|
|
838
|
+
// to every incoming change do no exactly agree with the rebased remote change (this happens
|
|
839
|
+
// when there are changes that cancel out with each other that have happened in the meantime).
|
|
840
|
+
// In that case, we must make sure, we correctly update the local view to take this difference into
|
|
841
|
+
// account by rebasing with respect to the changeset that is obtained by combining the inverse of the
|
|
842
|
+
// local change with the incoming remote change.
|
|
843
|
+
|
|
844
|
+
rebaseBaseChangeSet = new ChangeSet(this.localChanges.shift()?.changeSet);
|
|
845
|
+
rebaseBaseChangeSet.toInverseChangeSet();
|
|
846
|
+
rebaseBaseChangeSet.applyChangeSet(change.changeSet);
|
|
847
|
+
}
|
|
848
|
+
} else {
|
|
849
|
+
rebaseBaseChangeSet = cloneDeep(change.changeSet);
|
|
822
850
|
}
|
|
823
851
|
|
|
824
|
-
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
825
852
|
for (let i = 0; i < this.localChanges.length; i++) {
|
|
826
853
|
// Make sure we never receive changes out of order
|
|
827
854
|
console.assert(this.localChanges[i].guid !== change.guid);
|
|
@@ -845,6 +872,12 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
845
872
|
rebaseBaseChangeSet = copiedChangeSet.getSerializedChangeSet();
|
|
846
873
|
|
|
847
874
|
new ChangeSet(accumulatedChanges).applyChangeSet(this.localChanges[i].changeSet);
|
|
875
|
+
|
|
876
|
+
// Update the reference and head guids
|
|
877
|
+
this.localChanges[i].remoteHeadGuid = change.guid;
|
|
878
|
+
if (i === 0) {
|
|
879
|
+
this.localChanges[i].referenceGuid = change.guid;
|
|
880
|
+
}
|
|
848
881
|
}
|
|
849
882
|
|
|
850
883
|
// Compute the inverse of the pending changes and store the result in newTipDelta
|
|
@@ -874,6 +907,26 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
874
907
|
return true;
|
|
875
908
|
}
|
|
876
909
|
|
|
910
|
+
protected reSubmitCore(content: any, localOpMetadata: unknown) {
|
|
911
|
+
// We have to provide our own implementation of the resubmit core function, to
|
|
912
|
+
// handle the case where an operation is no longer referencing a commit within
|
|
913
|
+
// the collaboration window as its referenceGuid. Other clients would not be
|
|
914
|
+
// able to perform the rebase for such an operation. To handle this problem
|
|
915
|
+
// we have to resubmit a version of the operations which has been rebased to
|
|
916
|
+
// the current remote tip. We already have these rebased versions of the operations
|
|
917
|
+
// in our localChanges, because we continuously update those to follow the tip.
|
|
918
|
+
// Therefore our reSubmitCore function searches for the rebased operation in the
|
|
919
|
+
// localChanges array and submits this up-to-date version instead of the old operation.
|
|
920
|
+
const rebasedOperation = find(this.localChanges, (op) => op.guid === content.guid);
|
|
921
|
+
|
|
922
|
+
if (rebasedOperation) {
|
|
923
|
+
this.submitLocalMessage(cloneDeep(rebasedOperation), localOpMetadata);
|
|
924
|
+
} else {
|
|
925
|
+
// Could this happen or is there a guard that we will never resubmit an already submitted op?
|
|
926
|
+
console.warn("Resubmitting operation which has already been received back.");
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
877
930
|
protected applyStashedOp() {
|
|
878
931
|
throw new Error("not implemented");
|
|
879
932
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
6
6
|
import { deflate, inflate } from "pako";
|
|
7
7
|
import { compress, decompress } from "lz4js";
|
|
8
|
-
import { bufferToString, stringToBuffer } from "@
|
|
8
|
+
import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
|
|
9
9
|
import {
|
|
10
10
|
IChannelAttributes,
|
|
11
11
|
IFluidDataStoreRuntime,
|