use RBTree for in-memory storage
This commit is contained in:
parent
fe4564542b
commit
a1026bc365
@ -13,7 +13,7 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars
|
||||
if (op.id[1] === state.clock){
|
||||
state.clock++;
|
||||
yield* this.setState(state);
|
||||
yield* this.setOperation(op);
|
||||
this.os.add(op);
|
||||
this.store.operationAdded(op);
|
||||
return true;
|
||||
} else if (op.id[1] < state.clock) {
|
||||
@ -23,7 +23,6 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars
|
||||
}
|
||||
}
|
||||
}
|
||||
Y.AbstractTransaction = AbstractTransaction;
|
||||
|
||||
type Listener = {
|
||||
f : GeneratorFunction, // is called when all operations are available
|
||||
@ -187,4 +186,3 @@ class AbstractOperationStore { //eslint-disable-line no-unused-vars
|
||||
ls.push(f);
|
||||
}
|
||||
}
|
||||
Y.AbstractOperationStore = AbstractOperationStore;
|
||||
|
@ -29,14 +29,13 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
||||
this.os = store.os;
|
||||
}
|
||||
*setOperation (op) {
|
||||
if (op.struct === "Insert" && op.right === undefined) {
|
||||
throw new Error("here!");
|
||||
}
|
||||
this.os[JSON.stringify(op.id)] = op;
|
||||
// TODO: you can remove this step! probs..
|
||||
var n = this.os.findNode(op.id);
|
||||
n.val = op;
|
||||
return op;
|
||||
}
|
||||
*getOperation (id) {
|
||||
var op = this.os[JSON.stringify(id)];
|
||||
var op = this.os.find(id);
|
||||
if (op == null) {
|
||||
throw new Error("Op does not exist..");
|
||||
} else {
|
||||
@ -44,7 +43,7 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
||||
}
|
||||
}
|
||||
*removeOperation (id) {
|
||||
delete this.os[JSON.stringify(id)];
|
||||
this.os.delete(id);
|
||||
}
|
||||
*setState (state : State) : State {
|
||||
this.ss[state.user] = state.clock;
|
||||
@ -61,7 +60,6 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
||||
}
|
||||
*getStateVector () : StateVector {
|
||||
var stateVector = [];
|
||||
|
||||
for (var user in this.ss) {
|
||||
var clock = this.ss[user];
|
||||
stateVector.push({
|
||||
@ -75,6 +73,7 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
||||
return this.ss;
|
||||
}
|
||||
*getOperations (startSS : StateSet) {
|
||||
// TODO: use bounds here!
|
||||
if (startSS == null){
|
||||
startSS = {};
|
||||
}
|
||||
@ -89,15 +88,15 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
||||
var startPos = startSS[user] || 0;
|
||||
var endPos = endState.clock;
|
||||
|
||||
for (var clock = startPos; clock <= endPos; clock++) {
|
||||
var op = this.os[JSON.stringify([user, clock])];
|
||||
if (op != null) {
|
||||
op = Struct[op.struct].encode(op);
|
||||
ops.push(yield* this.makeOperationReady.call(this, startSS, op));
|
||||
}
|
||||
}
|
||||
this.os.iterate([user, startPos], [user, endPos], function(op){//eslint-disable-line
|
||||
ops.push(Struct[op.struct].encode(op));
|
||||
});
|
||||
}
|
||||
return ops;
|
||||
var res = [];
|
||||
for (var op of ops) {
|
||||
res.push(yield* this.makeOperationReady.call(this, startSS, op));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
*makeOperationReady (ss, op) {
|
||||
// instead of ss, you could use currSS (a ss that increments when you add an operation)
|
||||
@ -119,7 +118,7 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
||||
class OperationStore extends AbstractOperationStore { //eslint-disable-line no-undef
|
||||
constructor (y) {
|
||||
super(y);
|
||||
this.os = {};
|
||||
this.os = new RBTree();
|
||||
this.ss = {};
|
||||
}
|
||||
requestTransaction (makeGen : Function) {
|
||||
|
@ -1,6 +1,4 @@
|
||||
|
||||
|
||||
|
||||
class N {
|
||||
// A created node is always red!
|
||||
constructor (val) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* @flow */
|
||||
/*eslint-env browser,jasmine,console */
|
||||
|
||||
var numberOfTests = 10009;
|
||||
var numberOfRBTreeTests = 1000;
|
||||
|
||||
function itRedNodesDoNotHaveBlackChildren (tree) {
|
||||
it("Red nodes do not have black children", function(){
|
||||
@ -107,16 +107,15 @@ describe("RedBlack Tree", function(){
|
||||
|
||||
itRootNodeIsBlack(tree, []);
|
||||
itBlackHeightOfSubTreesAreEqual(tree, []);
|
||||
itRedNodesDoNotHaveBlackChildren(tree, []);
|
||||
});
|
||||
|
||||
describe(`After adding&deleting (0.8/0.2) ${numberOfTests} times`, function () {
|
||||
describe(`After adding&deleting (0.8/0.2) ${numberOfRBTreeTests} times`, function () {
|
||||
var elements = [];
|
||||
var tree = new RBTree();
|
||||
for(var i = 0; i < numberOfTests; i++) {
|
||||
for(var i = 0; i < numberOfRBTreeTests; i++) {
|
||||
var r = Math.random();
|
||||
if (r < 0.8) {
|
||||
var obj = Math.floor(Math.random() * numberOfTests * 10000);
|
||||
var obj = Math.floor(Math.random() * numberOfRBTreeTests * 10000);
|
||||
elements.push(obj);
|
||||
tree.add({id: obj});
|
||||
} else if (elements.length > 0) {
|
||||
|
@ -382,5 +382,3 @@ var Struct = {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Y.Struct = Struct;
|
||||
|
4
src/y.js
4
src/y.js
@ -31,3 +31,7 @@ class Y { //eslint-disable-line no-unused-vars
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Y.AbstractTransaction = AbstractTransaction;
|
||||
Y.AbstractOperationStore = AbstractOperationStore;
|
||||
Y.Struct = Struct;
|
||||
|
@ -21,16 +21,17 @@ function getRandomNumber(n) {
|
||||
return Math.floor(Math.random() * n);
|
||||
}
|
||||
var keys = ["a", "b", "c", "d", "e", "f", 1, 2, 3, 4, 5, 6];
|
||||
var numberOfTests = 500;
|
||||
var numberOfYMapTests = 20;
|
||||
|
||||
function applyRandomTransactions (users, transactions) {
|
||||
function applyRandomTransactions (users, transactions, numberOfTransactions) {
|
||||
function* randomTransaction (root) {
|
||||
var f = getRandom(transactions);
|
||||
yield* f(root);
|
||||
}
|
||||
for(var i = 0; i < numberOfTests; i++) {
|
||||
var r = getRandomNumber(100);
|
||||
if (r >= 50) {
|
||||
for(var i = 0; i < numberOfTransactions; i++) {
|
||||
var r = Math.random();
|
||||
if (r >= 0.9) {
|
||||
// 10% chance to flush
|
||||
users[0].connector.flushOne();
|
||||
} else {
|
||||
getRandom(users).transact(randomTransaction);
|
||||
@ -53,8 +54,15 @@ function compareAllUsers(users){
|
||||
u1.transact(t1);
|
||||
u2.transact(t2);
|
||||
expect(s1).toEqual(s2);
|
||||
var db1 = u1.db.os;
|
||||
var db2 = u2.db.os;
|
||||
var db1 = [];
|
||||
var db2 = [];
|
||||
u1.db.os.iterate(null, null, function(o){//eslint-disable-line
|
||||
db1.push(o);
|
||||
});
|
||||
u2.db.os.iterate(null, null, function(o){//eslint-disable-line
|
||||
db2.push(o);
|
||||
});
|
||||
|
||||
for (var key in db1) {
|
||||
expect(db1[key]).toEqual(db2[key]);
|
||||
}
|
||||
@ -195,13 +203,13 @@ describe("Yjs", function(){
|
||||
yield* map.val("getRandom(keys)", getRandomNumber());
|
||||
}
|
||||
];
|
||||
it(`succeed after ${numberOfTests} actions with flush before transactions`, function(){
|
||||
this.users[0].connector.flushAll(); // TODO: Remove!!
|
||||
applyRandomTransactions(this.users, randomMapTransactions);
|
||||
it(`succeed after ${numberOfYMapTests} actions with flush before transactions`, function(){
|
||||
this.users[0].connector.flushAll();
|
||||
applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
|
||||
compareAllUsers(this.users);
|
||||
});
|
||||
it(`succeed after ${numberOfTests} actions without flush before transactions`, function(){
|
||||
applyRandomTransactions(this.users, randomMapTransactions);
|
||||
it(`succeed after ${numberOfYMapTests} actions without flush before transactions`, function(){
|
||||
applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
|
||||
compareAllUsers(this.users);
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user