@fluid-experimental/property-dds 2.0.0-dev.5.3.2.178189 → 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 +24 -0
- package/dist/propertyTree.d.ts +2 -0
- package/dist/propertyTree.d.ts.map +1 -1
- package/dist/propertyTree.js +70 -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 +66 -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 -31
- package/src/propertyTree.ts +62 -13
- 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,28 +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/build-tools": "^0.
|
|
42
|
-
"@fluidframework/container-loader": "2.0.0-dev.
|
|
43
|
-
"@fluidframework/driver-definitions": "2.0.0-dev.
|
|
44
|
-
"@fluidframework/eslint-config-fluid": "^2.
|
|
45
|
-
"@fluidframework/local-driver": "2.0.0-dev.
|
|
46
|
-
"@fluidframework/mocha-test-setup": "2.0.0-dev.
|
|
47
|
-
"@fluidframework/sequence": "2.0.0-dev.
|
|
48
|
-
"@fluidframework/server-local-server": "^0.
|
|
49
|
-
"@fluidframework/test-runtime-utils": "2.0.0-dev.
|
|
50
|
-
"@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",
|
|
51
51
|
"@microsoft/api-extractor": "^7.34.4",
|
|
52
52
|
"@types/lodash": "^4.14.118",
|
|
53
53
|
"@types/mocha": "^9.1.1",
|
|
54
|
-
"@types/node": "^
|
|
54
|
+
"@types/node": "^16.18.38",
|
|
55
55
|
"chai": "^4.2.0",
|
|
56
|
-
"concurrently": "^7.6.0",
|
|
57
56
|
"copyfiles": "^2.4.1",
|
|
58
57
|
"cross-env": "^7.0.3",
|
|
59
58
|
"easy-table": "^1.1.1",
|
|
@@ -63,7 +62,6 @@
|
|
|
63
62
|
"mocha-json-output-reporter": "^2.0.1",
|
|
64
63
|
"mocha-multi-reporters": "^1.5.1",
|
|
65
64
|
"moment": "^2.21.0",
|
|
66
|
-
"nyc": "^15.1.0",
|
|
67
65
|
"prettier": "~2.6.2",
|
|
68
66
|
"rimraf": "^4.4.0",
|
|
69
67
|
"typescript": "~4.5.5"
|
|
@@ -79,7 +77,7 @@
|
|
|
79
77
|
"build:esnext": "tsc --project ./tsconfig.esnext.json",
|
|
80
78
|
"build:test": "tsc --project ./src/test/tsconfig.json",
|
|
81
79
|
"ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../../_api-extractor-temp/",
|
|
82
|
-
"clean": "rimraf dist lib *.tsbuildinfo *.build.log",
|
|
80
|
+
"clean": "rimraf --glob 'dist' 'lib' '*.tsbuildinfo' '*.build.log' '_api-extractor-temp' 'nyc'",
|
|
83
81
|
"eslint": "eslint src",
|
|
84
82
|
"eslint:fix": "eslint src --fix",
|
|
85
83
|
"format": "npm run prettier:fix",
|
|
@@ -88,9 +86,9 @@
|
|
|
88
86
|
"prettier": "prettier --check . --ignore-path ../../../../.prettierignore",
|
|
89
87
|
"prettier:fix": "prettier --write . --ignore-path ../../../../.prettierignore",
|
|
90
88
|
"test": "npm run test:mocha",
|
|
91
|
-
"test:mocha": "mocha \"dist/**/*.spec.js\" --exit -r node_modules/@fluidframework/mocha-test-setup
|
|
92
|
-
"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 --
|
|
93
|
-
"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",
|
|
94
92
|
"test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
|
|
95
93
|
"tsc": "tsc"
|
|
96
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() {
|
|
@@ -795,6 +800,10 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
795
800
|
|
|
796
801
|
getRebasedChanges(startGuid: string, endGuid?: string) {
|
|
797
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
|
+
}
|
|
798
807
|
if (endGuid !== undefined) {
|
|
799
808
|
const endIndex = findIndex(this.remoteChanges, (c) => c.guid === endGuid);
|
|
800
809
|
return this.remoteChanges.slice(startIndex + 1, endIndex + 1);
|
|
@@ -807,7 +816,7 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
807
816
|
pendingChanges: SerializedChangeSet,
|
|
808
817
|
newTipDelta: SerializedChangeSet,
|
|
809
818
|
): boolean {
|
|
810
|
-
let rebaseBaseChangeSet
|
|
819
|
+
let rebaseBaseChangeSet;
|
|
811
820
|
|
|
812
821
|
const accumulatedChanges: SerializedChangeSet = {};
|
|
813
822
|
const conflicts = [] as any[];
|
|
@@ -817,15 +826,29 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
817
826
|
// assert(JSON.stringify(this.localChanges[0].changeSet) === JSON.stringify(change.changeSet),
|
|
818
827
|
// "Local change different than rebased remote change.");
|
|
819
828
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
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();
|
|
824
834
|
|
|
825
|
-
|
|
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);
|
|
826
850
|
}
|
|
827
851
|
|
|
828
|
-
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
829
852
|
for (let i = 0; i < this.localChanges.length; i++) {
|
|
830
853
|
// Make sure we never receive changes out of order
|
|
831
854
|
console.assert(this.localChanges[i].guid !== change.guid);
|
|
@@ -849,6 +872,12 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
849
872
|
rebaseBaseChangeSet = copiedChangeSet.getSerializedChangeSet();
|
|
850
873
|
|
|
851
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
|
+
}
|
|
852
881
|
}
|
|
853
882
|
|
|
854
883
|
// Compute the inverse of the pending changes and store the result in newTipDelta
|
|
@@ -878,6 +907,26 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
878
907
|
return true;
|
|
879
908
|
}
|
|
880
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
|
+
|
|
881
930
|
protected applyStashedOp() {
|
|
882
931
|
throw new Error("not implemented");
|
|
883
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,
|