started refactoring the Memory db
This commit is contained in:
parent
181595293f
commit
aff10fa4db
@ -275,5 +275,28 @@ class AbstractDatabase {
|
|||||||
yield* t._changed(transaction, Y.utils.copyObject(op))
|
yield* t._changed(transaction, Y.utils.copyObject(op))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
getNextRequest () {
|
||||||
|
if (this.waitingTransactions.length === 0) {
|
||||||
|
this.transactionInProgress = false
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
return this.waitingTransactions.shift()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestTransaction (makeGen, callImmediately) {
|
||||||
|
if (!this.transactionInProgress) {
|
||||||
|
this.transactionInProgress = true
|
||||||
|
if (callImmediately) {
|
||||||
|
this.transact(makeGen)
|
||||||
|
} else {
|
||||||
|
var self = this
|
||||||
|
setTimeout(function () {
|
||||||
|
self.transact(makeGen)
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.waitingTransactions.push(makeGen)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Y.AbstractDatabase = AbstractDatabase
|
Y.AbstractDatabase = AbstractDatabase
|
||||||
|
@ -156,48 +156,48 @@ for (var database of databases) {
|
|||||||
})
|
})
|
||||||
it('debug #1', function (done) {
|
it('debug #1', function (done) {
|
||||||
store.requestTransaction(function * () {
|
store.requestTransaction(function * () {
|
||||||
yield this.os.put({id: [2]})
|
yield* this.os.put({id: [2]})
|
||||||
yield this.os.put({id: [0]})
|
yield* this.os.put({id: [0]})
|
||||||
yield this.os.delete([2])
|
yield* this.os.delete([2])
|
||||||
yield this.os.put({id: [1]})
|
yield* this.os.put({id: [1]})
|
||||||
expect(yield this.os.find([0])).not.toBeNull()
|
expect(yield* this.os.find([0])).not.toBeNull()
|
||||||
expect(yield this.os.find([1])).not.toBeNull()
|
expect(yield* this.os.find([1])).not.toBeNull()
|
||||||
expect(yield this.os.find([2])).toBeNull()
|
expect(yield* this.os.find([2])).toBeNull()
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
it('can add&retrieve 5 elements', function (done) {
|
it('can add&retrieve 5 elements', function (done) {
|
||||||
store.requestTransaction(function * () {
|
store.requestTransaction(function * () {
|
||||||
yield this.os.put({val: 'four', id: [4]})
|
yield* this.os.put({val: 'four', id: [4]})
|
||||||
yield this.os.put({val: 'one', id: [1]})
|
yield* this.os.put({val: 'one', id: [1]})
|
||||||
yield this.os.put({val: 'three', id: [3]})
|
yield* this.os.put({val: 'three', id: [3]})
|
||||||
yield this.os.put({val: 'two', id: [2]})
|
yield* this.os.put({val: 'two', id: [2]})
|
||||||
yield this.os.put({val: 'five', id: [5]})
|
yield* this.os.put({val: 'five', id: [5]})
|
||||||
expect((yield this.os.find([1])).val).toEqual('one')
|
expect((yield* this.os.find([1])).val).toEqual('one')
|
||||||
expect((yield this.os.find([2])).val).toEqual('two')
|
expect((yield* this.os.find([2])).val).toEqual('two')
|
||||||
expect((yield this.os.find([3])).val).toEqual('three')
|
expect((yield* this.os.find([3])).val).toEqual('three')
|
||||||
expect((yield this.os.find([4])).val).toEqual('four')
|
expect((yield* this.os.find([4])).val).toEqual('four')
|
||||||
expect((yield this.os.find([5])).val).toEqual('five')
|
expect((yield* this.os.find([5])).val).toEqual('five')
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
it('5 elements do not exist anymore after deleting them', function (done) {
|
it('5 elements do not exist anymore after deleting them', function (done) {
|
||||||
store.requestTransaction(function * () {
|
store.requestTransaction(function * () {
|
||||||
yield this.os.put({val: 'four', id: [4]})
|
yield* this.os.put({val: 'four', id: [4]})
|
||||||
yield this.os.put({val: 'one', id: [1]})
|
yield* this.os.put({val: 'one', id: [1]})
|
||||||
yield this.os.put({val: 'three', id: [3]})
|
yield* this.os.put({val: 'three', id: [3]})
|
||||||
yield this.os.put({val: 'two', id: [2]})
|
yield* this.os.put({val: 'two', id: [2]})
|
||||||
yield this.os.put({val: 'five', id: [5]})
|
yield* this.os.put({val: 'five', id: [5]})
|
||||||
yield this.os.delete([4])
|
yield* this.os.delete([4])
|
||||||
expect(yield this.os.find([4])).not.toBeTruthy()
|
expect(yield* this.os.find([4])).not.toBeTruthy()
|
||||||
yield this.os.delete([3])
|
yield* this.os.delete([3])
|
||||||
expect(yield this.os.find([3])).not.toBeTruthy()
|
expect(yield* this.os.find([3])).not.toBeTruthy()
|
||||||
yield this.os.delete([2])
|
yield* this.os.delete([2])
|
||||||
expect(yield this.os.find([2])).not.toBeTruthy()
|
expect(yield* this.os.find([2])).not.toBeTruthy()
|
||||||
yield this.os.delete([1])
|
yield* this.os.delete([1])
|
||||||
expect(yield this.os.find([1])).not.toBeTruthy()
|
expect(yield* this.os.find([1])).not.toBeTruthy()
|
||||||
yield this.os.delete([5])
|
yield* this.os.delete([5])
|
||||||
expect(yield this.os.find([5])).not.toBeTruthy()
|
expect(yield* this.os.find([5])).not.toBeTruthy()
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -214,9 +214,9 @@ for (var database of databases) {
|
|||||||
var r = Math.random()
|
var r = Math.random()
|
||||||
if (r < 0.8) {
|
if (r < 0.8) {
|
||||||
var obj = [Math.floor(Math.random() * numberOfOSTests * 10000)]
|
var obj = [Math.floor(Math.random() * numberOfOSTests * 10000)]
|
||||||
if (!(yield this.os.findNode(obj))) {
|
if (!(this.os.findNode(obj))) {
|
||||||
elements.push(obj)
|
elements.push(obj)
|
||||||
yield this.os.put({id: obj})
|
yield* this.os.put({id: obj})
|
||||||
}
|
}
|
||||||
} else if (elements.length > 0) {
|
} else if (elements.length > 0) {
|
||||||
var elemid = Math.floor(Math.random() * elements.length)
|
var elemid = Math.floor(Math.random() * elements.length)
|
||||||
@ -224,7 +224,7 @@ for (var database of databases) {
|
|||||||
elements = elements.filter(function (e) {
|
elements = elements.filter(function (e) {
|
||||||
return !Y.utils.compareIds(e, elem)
|
return !Y.utils.compareIds(e, elem)
|
||||||
})
|
})
|
||||||
yield this.os.delete(elem)
|
yield* this.os.delete(elem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done()
|
done()
|
||||||
@ -233,7 +233,7 @@ for (var database of databases) {
|
|||||||
it('can find every object', function (done) {
|
it('can find every object', function (done) {
|
||||||
store.requestTransaction(function * () {
|
store.requestTransaction(function * () {
|
||||||
for (var id of elements) {
|
for (var id of elements) {
|
||||||
expect((yield this.os.find(id)).id).toEqual(id)
|
expect((yield* this.os.find(id)).id).toEqual(id)
|
||||||
}
|
}
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
@ -242,7 +242,8 @@ for (var database of databases) {
|
|||||||
it('can find every object with lower bound search', function (done) {
|
it('can find every object with lower bound search', function (done) {
|
||||||
store.requestTransaction(function * () {
|
store.requestTransaction(function * () {
|
||||||
for (var id of elements) {
|
for (var id of elements) {
|
||||||
expect((yield this.os.findNodeWithLowerBound(id)).val.id).toEqual(id)
|
var e = yield* this.os.findNodeWithLowerBound(id)
|
||||||
|
expect(e.val.id).toEqual(id)
|
||||||
}
|
}
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
@ -3,43 +3,51 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
Y.IndexedDB = (function () {
|
Y.IndexedDB = (function () {
|
||||||
|
class Store {
|
||||||
|
constructor (transaction, name) {
|
||||||
|
this.store = transaction.objectStore(name)
|
||||||
|
}
|
||||||
|
find (id) {
|
||||||
|
return this.store.get(id)
|
||||||
|
}
|
||||||
|
put (v) {
|
||||||
|
return this.store.put(v)
|
||||||
|
}
|
||||||
|
delete (id) {
|
||||||
|
return this.store.delete(id)
|
||||||
|
}
|
||||||
|
* findNodeWithLowerBound (start) {
|
||||||
|
var cursorResult = this.store.openCursor(window.IDBKeyRange.lowerBound(start))
|
||||||
|
var cursor
|
||||||
|
while ((cursor = yield cursorResult) != null) {
|
||||||
|
// yield* gen.call(t, cursor.value)
|
||||||
|
cursor.continue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
* iterate (t, start, end, gen) {
|
||||||
|
var range = null
|
||||||
|
if (start != null && end != null) {
|
||||||
|
range = window.IDBKeyRange.bound(start, end)
|
||||||
|
} else if (start != null) {
|
||||||
|
range = window.IDBKeyRange.lowerBound(start)
|
||||||
|
} else if (end != null) {
|
||||||
|
range = window.IDBKeyRange.upperBound(end)
|
||||||
|
}
|
||||||
|
var cursorResult = this.store.openCursor(range)
|
||||||
|
var cursor
|
||||||
|
while ((cursor = yield cursorResult) != null) {
|
||||||
|
yield* gen.call(t, cursor.value)
|
||||||
|
cursor.continue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
class Transaction {
|
class Transaction {
|
||||||
constructor (store) {
|
constructor (store) {
|
||||||
this.transaction = store.db.transaction(['OperationStore', 'StateVector'], 'readwrite')
|
var transaction = store.db.transaction(['OperationStore', 'StateStore', 'DeleteStore'], 'readwrite')
|
||||||
this.sv = this.transaction.objectStore('StateVector')
|
this.ss = new Store(transaction, 'StateStore')
|
||||||
this.os = this.transaction.objectStore('OperationStore')
|
this.os = new Store(transaction, 'OperationStore')
|
||||||
this.buffer = {}
|
this.ds = new Store(transaction, 'DeleteStore')
|
||||||
}
|
|
||||||
* setOperation (op) {
|
|
||||||
yield this.os.put(op)
|
|
||||||
this.buffer[JSON.stringify(op.id)] = op
|
|
||||||
return op
|
|
||||||
}
|
|
||||||
* getOperation (id) {
|
|
||||||
var op = this.buffer[JSON.stringify(id)]
|
|
||||||
if (op == null) {
|
|
||||||
op = yield this.os.get(id)
|
|
||||||
this.buffer[JSON.stringify(id)] = op
|
|
||||||
}
|
|
||||||
return op
|
|
||||||
}
|
|
||||||
* removeOperation (id) {
|
|
||||||
this.buffer[JSON.stringify(id)] = null
|
|
||||||
return yield this.os.delete(id)
|
|
||||||
}
|
|
||||||
* setState (state) {
|
|
||||||
return yield this.sv.put(state)
|
|
||||||
}
|
|
||||||
* getState (user) {
|
|
||||||
var state
|
|
||||||
if ((state = yield this.sv.get(user)) != null) {
|
|
||||||
return state
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
user: user,
|
|
||||||
clock: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
* getStateVector () {
|
* getStateVector () {
|
||||||
var stateVector = []
|
var stateVector = []
|
||||||
@ -155,7 +163,8 @@ Y.IndexedDB = (function () {
|
|||||||
var db = event.target.result
|
var db = event.target.result
|
||||||
try {
|
try {
|
||||||
db.createObjectStore('OperationStore', {keyPath: 'id'})
|
db.createObjectStore('OperationStore', {keyPath: 'id'})
|
||||||
db.createObjectStore('StateVector', {keyPath: 'user'})
|
db.createObjectStore('DeleteStore', {keyPath: 'id'})
|
||||||
|
db.createObjectStore('StateStore', {keyPath: 'id'})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// console.log("Store already exists!")
|
// console.log("Store already exists!")
|
||||||
}
|
}
|
||||||
@ -172,7 +181,19 @@ Y.IndexedDB = (function () {
|
|||||||
this.transactionQueue.onRequest()
|
this.transactionQueue.onRequest()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
* removeDatabase () {
|
transact (makeGen) {
|
||||||
|
var t = new Y.Transaction(this)
|
||||||
|
while (makeGen !== null) {
|
||||||
|
var gen = makeGen.call(t)
|
||||||
|
var res = gen.next()
|
||||||
|
while (!res.done) {
|
||||||
|
res = gen.next(res.value)
|
||||||
|
}
|
||||||
|
makeGen = this.getNextRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: implement "free"..
|
||||||
|
* destroy () {
|
||||||
this.db.close()
|
this.db.close()
|
||||||
yield window.indexedDB.deleteDatabase(this.namespace)
|
yield window.indexedDB.deleteDatabase(this.namespace)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,15 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
Y.Memory = (function () {
|
Y.Memory = (function () {
|
||||||
|
class Transaction extends Y.Transaction {
|
||||||
|
constructor (store) {
|
||||||
|
super(store)
|
||||||
|
this.store = store
|
||||||
|
this.ss = store.ss
|
||||||
|
this.os = store.os
|
||||||
|
this.ds = store.ds
|
||||||
|
}
|
||||||
|
}
|
||||||
class Database extends Y.AbstractDatabase {
|
class Database extends Y.AbstractDatabase {
|
||||||
constructor (y, opts) {
|
constructor (y, opts) {
|
||||||
super(y, opts)
|
super(y, opts)
|
||||||
@ -25,29 +34,15 @@ Y.Memory = (function () {
|
|||||||
}, true)
|
}, true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
requestTransaction (_makeGen, callImmediately) {
|
transact (makeGen) {
|
||||||
if (!this.transactionInProgress) {
|
var t = new Transaction(this)
|
||||||
this.transactionInProgress = true
|
while (makeGen !== null) {
|
||||||
var transact = () => {
|
|
||||||
var makeGen = _makeGen
|
|
||||||
while (makeGen != null) {
|
|
||||||
var t = new Y.Transaction(this)
|
|
||||||
var gen = makeGen.call(t)
|
var gen = makeGen.call(t)
|
||||||
var res = gen.next()
|
var res = gen.next()
|
||||||
while (!res.done) {
|
while (!res.done) {
|
||||||
res = gen.next(res.value)
|
res = gen.next(res.value)
|
||||||
}
|
}
|
||||||
makeGen = this.waitingTransactions.shift()
|
makeGen = this.getNextRequest()
|
||||||
}
|
|
||||||
this.transactionInProgress = false
|
|
||||||
}
|
|
||||||
if (callImmediately) {
|
|
||||||
transact()
|
|
||||||
} else {
|
|
||||||
setTimeout(transact, 0)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.waitingTransactions.push(_makeGen)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
* destroy () {
|
* destroy () {
|
||||||
|
@ -130,7 +130,13 @@ class RBTree {
|
|||||||
this.root = null
|
this.root = null
|
||||||
this.length = 0
|
this.length = 0
|
||||||
}
|
}
|
||||||
findNodeWithLowerBound (from) {
|
* findNext (id) {
|
||||||
|
return yield* this.findNodeWithLowerBound([id[0], id[1] + 1])
|
||||||
|
}
|
||||||
|
* findPrev (id) {
|
||||||
|
return yield* this.findNodeWithUpperBound([id[0], id[1] - 1])
|
||||||
|
}
|
||||||
|
* findNodeWithLowerBound (from) {
|
||||||
if (from === void 0) {
|
if (from === void 0) {
|
||||||
throw new Error('You must define from!')
|
throw new Error('You must define from!')
|
||||||
}
|
}
|
||||||
@ -158,7 +164,7 @@ class RBTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
findNodeWithUpperBound (to) {
|
* findNodeWithUpperBound (to) {
|
||||||
if (to === void 0) {
|
if (to === void 0) {
|
||||||
throw new Error('You must define from!')
|
throw new Error('You must define from!')
|
||||||
}
|
}
|
||||||
@ -187,7 +193,7 @@ class RBTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
* iterate (t, from, to, f) {
|
* iterate (t, from, to, f) {
|
||||||
var o = this.findNodeWithLowerBound(from)
|
var o = yield* this.findNodeWithLowerBound(from)
|
||||||
while (o !== null && (to === null || Y.utils.smaller(o.val.id, to) || Y.utils.compareIds(o.val.id, to))) {
|
while (o !== null && (to === null || Y.utils.smaller(o.val.id, to) || Y.utils.compareIds(o.val.id, to))) {
|
||||||
yield* f.call(t, o.val)
|
yield* f.call(t, o.val)
|
||||||
o = o.next()
|
o = o.next()
|
||||||
@ -220,7 +226,7 @@ class RBTree {
|
|||||||
console.table(os)
|
console.table(os)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
find (id) {
|
* find (id) {
|
||||||
var n
|
var n
|
||||||
return (n = this.findNode(id)) ? n.val : null
|
return (n = this.findNode(id)) ? n.val : null
|
||||||
}
|
}
|
||||||
@ -246,7 +252,7 @@ class RBTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete (id) {
|
* delete (id) {
|
||||||
if (id == null || id.constructor !== Array) {
|
if (id == null || id.constructor !== Array) {
|
||||||
throw new Error('id is expected to be an Array!')
|
throw new Error('id is expected to be an Array!')
|
||||||
}
|
}
|
||||||
@ -388,7 +394,7 @@ class RBTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
put (v) {
|
* put (v) {
|
||||||
if (v == null || v.id == null || v.id.constructor !== Array) {
|
if (v == null || v.id == null || v.id.constructor !== Array) {
|
||||||
throw new Error('v is expected to have an id property which is an Array!')
|
throw new Error('v is expected to have an id property which is an Array!')
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
var numberOfRBTreeTests = 1000
|
var numberOfRBTreeTests = 1000
|
||||||
|
|
||||||
function itRedNodesDoNotHaveBlackChildren (tree) {
|
function itRedNodesDoNotHaveBlackChildren () {
|
||||||
it('Red nodes do not have black children', function () {
|
it('Red nodes do not have black children', function () {
|
||||||
function traverse (n) {
|
function traverse (n) {
|
||||||
if (n == null) {
|
if (n == null) {
|
||||||
@ -20,11 +20,11 @@ function itRedNodesDoNotHaveBlackChildren (tree) {
|
|||||||
traverse(n.left)
|
traverse(n.left)
|
||||||
traverse(n.right)
|
traverse(n.right)
|
||||||
}
|
}
|
||||||
traverse(tree.root)
|
traverse(this.tree.root)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function itBlackHeightOfSubTreesAreEqual (tree) {
|
function itBlackHeightOfSubTreesAreEqual () {
|
||||||
it('Black-height of sub-trees are equal', function () {
|
it('Black-height of sub-trees are equal', function () {
|
||||||
function traverse (n) {
|
function traverse (n) {
|
||||||
if (n == null) {
|
if (n == null) {
|
||||||
@ -39,50 +39,63 @@ function itBlackHeightOfSubTreesAreEqual (tree) {
|
|||||||
return sub1 + 1
|
return sub1 + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
traverse(tree.root)
|
traverse(this.tree.root)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function itRootNodeIsBlack (tree) {
|
function itRootNodeIsBlack () {
|
||||||
it('root node is black', function () {
|
it('root node is black', function () {
|
||||||
expect(tree.root == null || tree.root.isBlack()).toBeTruthy()
|
expect(this.tree.root == null || this.tree.root.isBlack()).toBeTruthy()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('RedBlack Tree', function () {
|
describe('RedBlack Tree', function () {
|
||||||
beforeEach(function () {
|
var tree, memory
|
||||||
|
describe('debug #2', function () {
|
||||||
|
beforeAll(function (done) {
|
||||||
this.memory = new Y.Memory(null, {
|
this.memory = new Y.Memory(null, {
|
||||||
name: 'Memory',
|
name: 'Memory',
|
||||||
gcTimeout: -1
|
gcTimeout: -1
|
||||||
})
|
})
|
||||||
this.tree = this.memory.os
|
this.tree = this.memory.os
|
||||||
|
tree = this.tree
|
||||||
|
memory = this.memory
|
||||||
|
memory.requestTransaction(function * () {
|
||||||
|
yield* tree.put({id: [8433]})
|
||||||
|
yield* tree.put({id: [12844]})
|
||||||
|
yield* tree.put({id: [1795]})
|
||||||
|
yield* tree.put({id: [30302]})
|
||||||
|
yield* tree.put({id: [64287]})
|
||||||
|
yield* tree.delete([8433])
|
||||||
|
yield* tree.put({id: [28996]})
|
||||||
|
yield* tree.delete([64287])
|
||||||
|
yield* tree.put({id: [22721]})
|
||||||
|
done()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
describe('debug #2', function () {
|
|
||||||
var tree = new Y.utils.RBTree()
|
|
||||||
tree.put({id: [8433]})
|
|
||||||
tree.put({id: [12844]})
|
|
||||||
tree.put({id: [1795]})
|
|
||||||
tree.put({id: [30302]})
|
|
||||||
tree.put({id: [64287]})
|
|
||||||
tree.delete([8433])
|
|
||||||
tree.put({id: [28996]})
|
|
||||||
tree.delete([64287])
|
|
||||||
tree.put({id: [22721]})
|
|
||||||
|
|
||||||
itRootNodeIsBlack(tree, [])
|
itRootNodeIsBlack()
|
||||||
itBlackHeightOfSubTreesAreEqual(tree, [])
|
itBlackHeightOfSubTreesAreEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
describe(`After adding&deleting (0.8/0.2) ${numberOfRBTreeTests} times`, function () {
|
describe(`After adding&deleting (0.8/0.2) ${numberOfRBTreeTests} times`, function () {
|
||||||
var elements = []
|
var elements = []
|
||||||
var tree = new Y.utils.RBTree()
|
beforeAll(function (done) {
|
||||||
|
this.memory = new Y.Memory(null, {
|
||||||
|
name: 'Memory',
|
||||||
|
gcTimeout: -1
|
||||||
|
})
|
||||||
|
this.tree = this.memory.os
|
||||||
|
tree = this.tree
|
||||||
|
memory = this.memory
|
||||||
|
memory.requestTransaction(function * () {
|
||||||
for (var i = 0; i < numberOfRBTreeTests; i++) {
|
for (var i = 0; i < numberOfRBTreeTests; i++) {
|
||||||
var r = Math.random()
|
var r = Math.random()
|
||||||
if (r < 0.8) {
|
if (r < 0.8) {
|
||||||
var obj = [Math.floor(Math.random() * numberOfRBTreeTests * 10000)]
|
var obj = [Math.floor(Math.random() * numberOfRBTreeTests * 10000)]
|
||||||
if (!tree.findNode(obj)) {
|
if (!tree.findNode(obj)) {
|
||||||
elements.push(obj)
|
elements.push(obj)
|
||||||
tree.put({id: obj})
|
yield* tree.put({id: obj})
|
||||||
}
|
}
|
||||||
} else if (elements.length > 0) {
|
} else if (elements.length > 0) {
|
||||||
var elemid = Math.floor(Math.random() * elements.length)
|
var elemid = Math.floor(Math.random() * elements.length)
|
||||||
@ -90,25 +103,35 @@ describe('RedBlack Tree', function () {
|
|||||||
elements = elements.filter(function (e) {
|
elements = elements.filter(function (e) {
|
||||||
return !Y.utils.compareIds(e, elem)
|
return !Y.utils.compareIds(e, elem)
|
||||||
})
|
})
|
||||||
tree.delete(elem)
|
yield* tree.delete(elem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
itRootNodeIsBlack(tree)
|
done()
|
||||||
|
})
|
||||||
it('can find every object', function () {
|
|
||||||
for (var id of elements) {
|
|
||||||
expect(tree.find(id).id).toEqual(id)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can find every object with lower bound search', function () {
|
itRootNodeIsBlack()
|
||||||
for (var id of elements) {
|
|
||||||
expect(tree.findNodeWithLowerBound(id).val.id).toEqual(id)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
itRedNodesDoNotHaveBlackChildren(tree)
|
|
||||||
|
|
||||||
itBlackHeightOfSubTreesAreEqual(tree)
|
it('can find every object', function (done) {
|
||||||
|
memory.requestTransaction(function * () {
|
||||||
|
for (var id of elements) {
|
||||||
|
expect((yield* tree.find(id)).id).toEqual(id)
|
||||||
|
}
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can find every object with lower bound search', function (done) {
|
||||||
|
this.memory.requestTransaction(function * () {
|
||||||
|
for (var id of elements) {
|
||||||
|
expect((yield* tree.findNodeWithLowerBound(id)).val.id).toEqual(id)
|
||||||
|
}
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
itRedNodesDoNotHaveBlackChildren()
|
||||||
|
|
||||||
|
itBlackHeightOfSubTreesAreEqual()
|
||||||
|
|
||||||
it('iterating over a tree with lower bound yields the right amount of results', function (done) {
|
it('iterating over a tree with lower bound yields the right amount of results', function (done) {
|
||||||
var lowerBound = elements[Math.floor(Math.random() * elements.length)]
|
var lowerBound = elements[Math.floor(Math.random() * elements.length)]
|
||||||
|
@ -18,7 +18,7 @@ g.g = g
|
|||||||
|
|
||||||
g.YConcurrency_TestingMode = true
|
g.YConcurrency_TestingMode = true
|
||||||
|
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000
|
||||||
|
|
||||||
g.describeManyTimes = function describeManyTimes (times, name, f) {
|
g.describeManyTimes = function describeManyTimes (times, name, f) {
|
||||||
for (var i = 0; i < times; i++) {
|
for (var i = 0; i < times; i++) {
|
||||||
@ -36,7 +36,7 @@ function wait (t) {
|
|||||||
return new Promise(function (resolve) {
|
return new Promise(function (resolve) {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
resolve()
|
resolve()
|
||||||
}, t)
|
}, t * 2)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
g.wait = wait
|
g.wait = wait
|
||||||
|
@ -75,12 +75,6 @@
|
|||||||
applyable on a given SS.
|
applyable on a given SS.
|
||||||
*/
|
*/
|
||||||
class Transaction {
|
class Transaction {
|
||||||
constructor (store) {
|
|
||||||
this.store = store
|
|
||||||
this.ss = store.ss
|
|
||||||
this.os = store.os
|
|
||||||
this.ds = store.ds
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
Get a type based on the id of its model.
|
Get a type based on the id of its model.
|
||||||
If it does not exist yes, create it.
|
If it does not exist yes, create it.
|
||||||
@ -206,14 +200,14 @@ class Transaction {
|
|||||||
// un-extend left
|
// un-extend left
|
||||||
var newlen = n.val.len - (id[1] - n.val.id[1])
|
var newlen = n.val.len - (id[1] - n.val.id[1])
|
||||||
n.val.len -= newlen
|
n.val.len -= newlen
|
||||||
n = yield this.ds.put({id: id, len: newlen, gc: false})
|
n = yield* this.ds.put({id: id, len: newlen, gc: false})
|
||||||
}
|
}
|
||||||
// get prev&next before adding a new operation
|
// get prev&next before adding a new operation
|
||||||
var prev = n.prev()
|
var prev = n.prev()
|
||||||
var next = n.next()
|
var next = n.next()
|
||||||
if (id[1] < n.val.id[1] + n.val.len - 1) {
|
if (id[1] < n.val.id[1] + n.val.len - 1) {
|
||||||
// un-extend right
|
// un-extend right
|
||||||
yield this.ds.put({id: [id[0], id[1] + 1], len: n.val.len - 1, gc: false})
|
yield* this.ds.put({id: [id[0], id[1] + 1], len: n.val.len - 1, gc: false})
|
||||||
n.val.len = 1
|
n.val.len = 1
|
||||||
}
|
}
|
||||||
// set gc'd
|
// set gc'd
|
||||||
@ -225,7 +219,7 @@ class Transaction {
|
|||||||
Y.utils.compareIds([prev.val.id[0], prev.val.id[1] + prev.val.len], n.val.id)
|
Y.utils.compareIds([prev.val.id[0], prev.val.id[1] + prev.val.len], n.val.id)
|
||||||
) {
|
) {
|
||||||
prev.val.len += n.val.len
|
prev.val.len += n.val.len
|
||||||
yield this.ds.delete(n.val.id)
|
yield* this.ds.delete(n.val.id)
|
||||||
n = prev
|
n = prev
|
||||||
}
|
}
|
||||||
// can extend right?
|
// can extend right?
|
||||||
@ -235,7 +229,7 @@ class Transaction {
|
|||||||
Y.utils.compareIds([n.val.id[0], n.val.id[1] + n.val.len], next.val.id)
|
Y.utils.compareIds([n.val.id[0], n.val.id[1] + n.val.len], next.val.id)
|
||||||
) {
|
) {
|
||||||
n.val.len += next.val.len
|
n.val.len += next.val.len
|
||||||
yield this.ds.delete(next.val.id)
|
yield* this.ds.delete(next.val.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,7 +240,7 @@ class Transaction {
|
|||||||
*/
|
*/
|
||||||
* markDeleted (id) {
|
* markDeleted (id) {
|
||||||
// this.mem.push(["del", id]);
|
// this.mem.push(["del", id]);
|
||||||
var n = yield this.ds.findNodeWithUpperBound(id)
|
var n = yield* this.ds.findNodeWithUpperBound(id)
|
||||||
if (n != null && n.val.id[0] === id[0]) {
|
if (n != null && n.val.id[0] === id[0]) {
|
||||||
if (n.val.id[1] <= id[1] && id[1] < n.val.id[1] + n.val.len) {
|
if (n.val.id[1] <= id[1] && id[1] < n.val.id[1] + n.val.len) {
|
||||||
// already deleted
|
// already deleted
|
||||||
@ -256,11 +250,11 @@ class Transaction {
|
|||||||
n.val.len++
|
n.val.len++
|
||||||
} else {
|
} else {
|
||||||
// cannot extend left
|
// cannot extend left
|
||||||
n = yield this.ds.put({id: id, len: 1, gc: false})
|
n = yield* this.ds.put({id: id, len: 1, gc: false})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// cannot extend left
|
// cannot extend left
|
||||||
n = yield this.ds.put({id: id, len: 1, gc: false})
|
n = yield* this.ds.put({id: id, len: 1, gc: false})
|
||||||
}
|
}
|
||||||
// can extend right?
|
// can extend right?
|
||||||
var next = n.next()
|
var next = n.next()
|
||||||
@ -270,8 +264,8 @@ class Transaction {
|
|||||||
!next.val.gc
|
!next.val.gc
|
||||||
) {
|
) {
|
||||||
n.val.len = n.val.len + next.val.len
|
n.val.len = n.val.len + next.val.len
|
||||||
yield this.ds.delete(next.val.id)
|
yield* this.ds.delete(next.val.id)
|
||||||
return yield this.ds.findNode(n.val.id)
|
return this.ds.findNode(n.val.id)
|
||||||
} else {
|
} else {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
@ -389,7 +383,7 @@ class Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
* checkDeleteStoreForState (state) {
|
* checkDeleteStoreForState (state) {
|
||||||
var n = yield this.ds.findNodeWithUpperBound([state.user, state.clock])
|
var n = yield* this.ds.findNodeWithUpperBound([state.user, state.clock])
|
||||||
if (n !== null && n.val.id[0] === state.user && n.val.gc) {
|
if (n !== null && n.val.id[0] === state.user && n.val.gc) {
|
||||||
state.clock = Math.max(state.clock, n.val.id[1] + n.val.len)
|
state.clock = Math.max(state.clock, n.val.id[1] + n.val.len)
|
||||||
}
|
}
|
||||||
@ -468,7 +462,7 @@ class Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
* isGarbageCollected (id) {
|
* isGarbageCollected (id) {
|
||||||
var n = yield this.ds.findNodeWithUpperBound(id)
|
var n = yield* this.ds.findNodeWithUpperBound(id)
|
||||||
return n !== null && n.val.id[0] === id[0] && id[1] < n.val.id[1] + n.val.len && n.val.gc
|
return n !== null && n.val.id[0] === id[0] && id[1] < n.val.id[1] + n.val.len && n.val.gc
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -491,15 +485,15 @@ class Transaction {
|
|||||||
return ds
|
return ds
|
||||||
}
|
}
|
||||||
* isDeleted (id) {
|
* isDeleted (id) {
|
||||||
var n = yield this.ds.findNodeWithUpperBound(id)
|
var n = yield* this.ds.findNodeWithUpperBound(id)
|
||||||
return n !== null && n.val.id[0] === id[0] && id[1] < n.val.id[1] + n.val.len
|
return n !== null && n.val.id[0] === id[0] && id[1] < n.val.id[1] + n.val.len
|
||||||
}
|
}
|
||||||
* setOperation (op) {
|
* setOperation (op) {
|
||||||
yield this.os.put(op)
|
yield* this.os.put(op)
|
||||||
return op
|
return op
|
||||||
}
|
}
|
||||||
* addOperation (op) {
|
* addOperation (op) {
|
||||||
var n = yield this.os.put(op)
|
var n = yield* this.os.put(op)
|
||||||
return function () {
|
return function () {
|
||||||
if (n != null) {
|
if (n != null) {
|
||||||
n = n.next()
|
n = n.next()
|
||||||
@ -510,10 +504,10 @@ class Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
* getOperation (id) {
|
* getOperation (id) {
|
||||||
return yield this.os.find(id)
|
return yield* this.os.find(id)
|
||||||
}
|
}
|
||||||
* removeOperation (id) {
|
* removeOperation (id) {
|
||||||
yield this.os.delete(id)
|
yield* this.os.delete(id)
|
||||||
}
|
}
|
||||||
* setState (state) {
|
* setState (state) {
|
||||||
var val = {
|
var val = {
|
||||||
@ -521,15 +515,15 @@ class Transaction {
|
|||||||
clock: state.clock
|
clock: state.clock
|
||||||
}
|
}
|
||||||
// TODO: find a way to skip this step.. (after implementing some dbs..)
|
// TODO: find a way to skip this step.. (after implementing some dbs..)
|
||||||
if (yield this.ss.find([state.user])) {
|
if (yield* this.ss.find([state.user])) {
|
||||||
yield this.ss.put(val)
|
yield* this.ss.put(val)
|
||||||
} else {
|
} else {
|
||||||
yield this.ss.put(val)
|
yield* this.ss.put(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
* getState (user) {
|
* getState (user) {
|
||||||
var n
|
var n
|
||||||
var clock = (n = this.ss.find([user])) == null ? null : n.clock
|
var clock = (n = yield* this.ss.find([user])) == null ? null : n.clock
|
||||||
if (clock == null) {
|
if (clock == null) {
|
||||||
clock = 0
|
clock = 0
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* global createUsers, wait, Y, compareAllUsers, getRandomNumber, applyRandomTransactionsAllRejoinNoGC, applyRandomTransactionsWithGC, async, garbageCollectAllUsers, describeManyTimes */
|
/* global createUsers, wait, Y, compareAllUsers, getRandomNumber, applyRandomTransactionsAllRejoinNoGC, applyRandomTransactionsWithGC, async, garbageCollectAllUsers, describeManyTimes */
|
||||||
/* eslint-env browser,jasmine */
|
/* eslint-env browser,jasmine */
|
||||||
|
|
||||||
var numberOfYArrayTests = 10
|
var numberOfYArrayTests = 200
|
||||||
var repeatArrayTests = 1
|
var repeatArrayTests = 1
|
||||||
|
|
||||||
describe('Array Type', function () {
|
describe('Array Type', function () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user