started implementing the garbage collector
This commit is contained in:
		
							parent
							
								
									dae0f71cbc
								
							
						
					
					
						commit
						c8ded24842
					
				| @ -133,7 +133,7 @@ gulp.task('build_jasmine_browser', function () { | ||||
|     .pipe(gulp.dest('build')) | ||||
| }) | ||||
| 
 | ||||
| gulp.task('develop', ['build_jasmine_browser', 'build'], function () { | ||||
| gulp.task('develop', ['build_jasmine_browser'], function () { | ||||
|   gulp.watch(files.test, ['build_jasmine_browser']) | ||||
|   // gulp.watch(files.test, ["test"])
 | ||||
|   gulp.watch(files.test, ['build']) | ||||
|  | ||||
| @ -99,7 +99,9 @@ async function compareAllUsers(users){//eslint-disable-line | ||||
|         var d = ds[j] | ||||
|         for (var i = 0; i < d.len; i++) { | ||||
|           var o = yield* this.getOperation([d.id[0], d.id[1] + i]) | ||||
|           expect(o.deleted).toBeTruthy() | ||||
|           if (o != null) { | ||||
|             expect(o.deleted).toBeTruthy() | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }) | ||||
| @ -139,7 +141,8 @@ async function createUsers(self, numberOfUsers) {//eslint-disable-line | ||||
|   for (var i = 0; i < numberOfUsers; i++) { | ||||
|     promises.push(Y({ | ||||
|       db: { | ||||
|         name: 'Memory' | ||||
|         name: 'Memory', | ||||
|         gcTimeout: -1 | ||||
|       }, | ||||
|       connector: { | ||||
|         name: 'Test', | ||||
|  | ||||
| @ -39,7 +39,7 @@ class AbstractTransaction { // eslint-disable-line no-unused-vars | ||||
| } | ||||
| 
 | ||||
| class AbstractOperationStore { // eslint-disable-line no-unused-vars
 | ||||
|   constructor (y) { | ||||
|   constructor (y, opts) { | ||||
|     this.y = y | ||||
|     // E.g. this.listenersById[id] : Array<Listener>
 | ||||
|     this.listenersById = {} | ||||
| @ -62,6 +62,44 @@ class AbstractOperationStore { // eslint-disable-line no-unused-vars | ||||
|     this.initializedTypes = {} | ||||
|     this.whenUserIdSetListener = null | ||||
|     this.waitingOperations = new RBTree() | ||||
| 
 | ||||
|     this.gc1 = [] // first stage
 | ||||
|     this.gc2 = [] // second stage -> after that, kill it
 | ||||
|     this.gcTimeout = opts.gcTimeout || 5000 | ||||
|     var os = this | ||||
|     function garbageCollect () { | ||||
|       os.requestTransaction(function * () { | ||||
|         for (var i in os.gc2) { | ||||
|           var oid = os.gc2[i] | ||||
|           var o = yield* this.getOperation(oid) | ||||
|           if (o.left != null) { | ||||
|             var left = yield* this.getOperation(o.left) | ||||
|             left.right = o.right | ||||
|           } | ||||
|           if (o.right != null) { | ||||
|             var right = yield* this.getOperation(o.right) | ||||
|             right.left = o.left | ||||
|           } | ||||
|           yield* this.removeOperation(o.id) | ||||
|         } | ||||
|         os.gc2 = os.gc1 | ||||
|         os.gc1 = [] | ||||
|         if (os.gcTimeout > 0) { | ||||
|           os.gcInterval = setTimeout(garbageCollect, os.gcTimeout) | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|     this.garbageCollect = garbageCollect | ||||
|     if (this.gcTimeout > 0) { | ||||
|       garbageCollect() | ||||
|     } | ||||
|   } | ||||
|   addToGarbageCollector (op) { | ||||
|     this.gc1.push(op) | ||||
|   } | ||||
|   destroy () { | ||||
|     clearInterval(this.gcInterval) | ||||
|     this.gcInterval = null | ||||
|   } | ||||
|   setUserId (userId) { | ||||
|     this.userId = userId | ||||
| @ -201,7 +239,7 @@ class AbstractOperationStore { // eslint-disable-line no-unused-vars | ||||
|     } | ||||
|     // notify parent, if it has been initialized as a custom type
 | ||||
|     var t = this.initializedTypes[JSON.stringify(op.parent)] | ||||
|     if (t != null) { | ||||
|     if (t != null && !op.deleted) { | ||||
|       yield* t._changed(transaction, copyObject(op)) | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @ -81,7 +81,7 @@ Y.IndexedDB = (function () { // eslint-disable-line | ||||
|   } | ||||
|   class OperationStore extends AbstractOperationStore { // eslint-disable-line no-undef
 | ||||
|     constructor (y, opts) { | ||||
|       super(y) | ||||
|       super(y, opts) | ||||
|       if (opts == null) { | ||||
|         opts = {} | ||||
|       } | ||||
|  | ||||
| @ -6,7 +6,7 @@ if (typeof window !== 'undefined') { | ||||
|   describe('IndexedDB', function () { | ||||
|     var ob | ||||
|     beforeAll(function () { | ||||
|       ob = new Y.IndexedDB(null, {namespace: 'Test'}) | ||||
|       ob = new Y.IndexedDB(null, {namespace: 'Test', gcTimeout: -1}) | ||||
|     }) | ||||
| 
 | ||||
|     it('can add and get operation', function (done) { | ||||
|  | ||||
| @ -238,8 +238,8 @@ Y.Memory = (function () { // eslint-disable-line no-unused-vars | ||||
|     } | ||||
|   } | ||||
|   class OperationStore extends AbstractOperationStore { // eslint-disable-line no-undef
 | ||||
|     constructor (y) { | ||||
|       super(y) | ||||
|     constructor (y, opts) { | ||||
|       super(y, opts) | ||||
|       this.os = new RBTree() | ||||
|       this.ss = {} | ||||
|       this.waitingTransactions = [] | ||||
| @ -249,10 +249,10 @@ Y.Memory = (function () { // eslint-disable-line no-unused-vars | ||||
|     logTable () { | ||||
|       this.os.logTable() | ||||
|     } | ||||
|     requestTransaction (_makeGen) { | ||||
|     requestTransaction (_makeGen, requestNow = false) { | ||||
|       if (!this.transactionInProgress) { | ||||
|         this.transactionInProgress = true | ||||
|         setTimeout(() => { | ||||
|         var transact = () => { | ||||
|           var makeGen = _makeGen | ||||
|           while (makeGen != null) { | ||||
|             var t = new Transaction(this) | ||||
| @ -268,12 +268,18 @@ Y.Memory = (function () { // eslint-disable-line no-unused-vars | ||||
|             makeGen = this.waitingTransactions.shift() | ||||
|           } | ||||
|           this.transactionInProgress = false | ||||
|         }, 0) | ||||
|         } | ||||
|         if (!requestNow) { | ||||
|           setTimeout(transact, 0) | ||||
|         } else { | ||||
|           transact() | ||||
|         } | ||||
|       } else { | ||||
|         this.waitingTransactions.push(_makeGen) | ||||
|       } | ||||
|     } | ||||
|     * removeDatabase () { // eslint-disable-line
 | ||||
|     * destroy () { // eslint-disable-line
 | ||||
|       super.destroy() | ||||
|       delete this.os | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @ -31,6 +31,18 @@ var Struct = { | ||||
|       var target = yield* this.getOperation(op.target) | ||||
|       if (!target.deleted) { | ||||
|         target.deleted = true | ||||
|         if (target.left !== null && (yield* this.getOperation(target.left)).deleted) { | ||||
|           this.store.addToGarbageCollector(target.id) | ||||
|           target.gc = true | ||||
|         } | ||||
|         if (target.right !== null) { | ||||
|           var right = yield* this.getOperation(target.right) | ||||
|           if (right.deleted && right.gc == null) { | ||||
|             this.store.addToGarbageCollector(right.id) | ||||
|             right.gc = true | ||||
|             yield* this.setOperation(right) | ||||
|           } | ||||
|         } | ||||
|         yield* this.setOperation(target) | ||||
|         this.ds.delete(target.id) | ||||
|         var t = this.store.initializedTypes[JSON.stringify(target.parent)] | ||||
|  | ||||
| @ -179,6 +179,27 @@ describe('Array Type', function () { | ||||
|       await wait(50) | ||||
|       done() | ||||
|     }) | ||||
|     it('garbage collects', async function (done) { | ||||
|       var l1, l2, l3 | ||||
|       l1 = await y1.set('Array', Y.Array) | ||||
|       l1.insert(0, ['x', 'y', 'z']) | ||||
|       await flushAll() | ||||
|       yconfig1.disconnect() | ||||
|       l1.delete(0, 3) | ||||
|       l2 = await y2.get('Array') | ||||
|       await wait() | ||||
|       yconfig1.reconnect() | ||||
|       await wait() | ||||
|       l3 = await y3.get('Array') | ||||
|       await flushAll() | ||||
|       yconfig1.db.garbageCollect() | ||||
|       yconfig1.db.garbageCollect() | ||||
|       yconfig1.db.logTable() | ||||
|       expect(l1.toArray()).toEqual(l2.toArray()) | ||||
|       expect(l2.toArray()).toEqual(l3.toArray()) | ||||
|       expect(l2.toArray()).toEqual([]) | ||||
|       done() | ||||
|     }) | ||||
|   }) | ||||
|   describe(`Random tests`, function () { | ||||
|     var randomArrayTransactions = [ | ||||
|  | ||||
| @ -34,10 +34,18 @@ | ||||
|             if (op.left === null) { | ||||
|               if (op.opContent != null) { | ||||
|                 delete this.contents[key] | ||||
|                 this.opContents[key] = op.opContent | ||||
|                 if (op.deleted) { | ||||
|                   delete this.opContents[key] | ||||
|                 } else { | ||||
|                   this.opContents[key] = op.opContent | ||||
|                 } | ||||
|               } else { | ||||
|                 delete this.opContents[key] | ||||
|                 this.contents[key] = op.content | ||||
|                 if (op.deleted) { | ||||
|                   delete this.contents[key] | ||||
|                 } else { | ||||
|                   this.contents[key] = op.content | ||||
|                 } | ||||
|               } | ||||
|               this.map[key] = op.id | ||||
|               var insertEvent = { | ||||
| @ -54,11 +62,8 @@ | ||||
|             } | ||||
|           } else if (op.struct === 'Delete') { | ||||
|             if (compareIds(this.map[key], op.target)) { | ||||
|               if (this.opContents[key] != null) { | ||||
|                 delete this.opContents[key] | ||||
|               } else { | ||||
|                 delete this.contents[key] | ||||
|               } | ||||
|               delete this.opContents[key] | ||||
|               delete this.contents[key] | ||||
|               var deleteEvent = { | ||||
|                 name: key, | ||||
|                 object: this, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user