Improvements that are required for offline editing

This commit is contained in:
Kevin Jahns 2016-01-23 01:02:01 +01:00
parent 364ed325b0
commit 38bf398709
7 changed files with 46 additions and 29 deletions

View File

@ -94,7 +94,7 @@ module.exports = function (gulp, helperOptions) {
return browserify({ return browserify({
entries: files.specs, entries: files.specs,
debug: options.debug debug: true
}).bundle() }).bundle()
.pipe(source('specs.js')) .pipe(source('specs.js'))
.pipe(buffer()) .pipe(buffer())

View File

@ -54,7 +54,7 @@ require('./gulpfile.helper.js')(gulp, {
moduleName: 'yjs', moduleName: 'yjs',
includeRuntime: true, includeRuntime: true,
specs: [ specs: [
'./src/Types/Map.spec.js', '../y-array/src/Array.spec.js',
'./src/Database.spec.js' './src/Database.spec.js'
] ]
}) })

View File

@ -39,6 +39,13 @@ module.exports = function (Y /* :any */) {
*/ */
constructor (y, opts) { constructor (y, opts) {
this.y = y this.y = y
var os = this
this.userId = null
var resolve
this.userIdPromise = new Promise(function (r) {
resolve = r
})
this.userIdPromise.resolve = resolve
// whether to broadcast all applied operations (insert & delete hook) // whether to broadcast all applied operations (insert & delete hook)
this.forwardAppliedOperations = false this.forwardAppliedOperations = false
// E.g. this.listenersById[id] : Array<Listener> // E.g. this.listenersById[id] : Array<Listener>
@ -60,16 +67,15 @@ module.exports = function (Y /* :any */) {
// TODO: Use ES7 Weak Maps. This way types that are no longer user, // TODO: Use ES7 Weak Maps. This way types that are no longer user,
// wont be kept in memory. // wont be kept in memory.
this.initializedTypes = {} this.initializedTypes = {}
this.whenUserIdSetListener = null
this.waitingTransactions = [] this.waitingTransactions = []
this.transactionInProgress = false this.transactionInProgress = false
this.transactionIsFlushed = false
if (typeof YConcurrency_TestingMode !== 'undefined') { if (typeof YConcurrency_TestingMode !== 'undefined') {
this.executeOrder = [] this.executeOrder = []
} }
this.gc1 = [] // first stage this.gc1 = [] // first stage
this.gc2 = [] // second stage -> after that, remove the op this.gc2 = [] // second stage -> after that, remove the op
this.gcTimeout = opts.gcTimeout || 5000 this.gcTimeout = opts.gcTimeout || 5000
var os = this
function garbageCollect () { function garbageCollect () {
return os.whenTransactionsFinished().then(function () { return os.whenTransactionsFinished().then(function () {
if (os.gc1.length > 0 || os.gc2.length > 0) { if (os.gc1.length > 0 || os.gc2.length > 0) {
@ -175,26 +181,20 @@ module.exports = function (Y /* :any */) {
this.gcInterval = null this.gcInterval = null
} }
setUserId (userId) { setUserId (userId) {
var self = this if (!this.userIdPromise.inProgress) {
return new Promise(function (resolve) { this.userIdPromise.inProgress = true
var self = this
self.requestTransaction(function * () { self.requestTransaction(function * () {
self.userId = userId self.userId = userId
var state = yield* this.getState(userId) var state = yield* this.getState(userId)
self.opClock = state.clock self.opClock = state.clock
if (self.whenUserIdSetListener != null) { self.userIdPromise.resolve(userId)
self.whenUserIdSetListener()
self.whenUserIdSetListener = null
}
resolve()
}) })
}) }
return this.userIdPromise
} }
whenUserIdSet (f) { whenUserIdSet (f) {
if (this.userId != null) { this.userIdPromise.then(f)
f()
} else {
this.whenUserIdSetListener = f
}
} }
getNextOpId () { getNextOpId () {
if (this._nextUserId != null) { if (this._nextUserId != null) {
@ -390,15 +390,26 @@ module.exports = function (Y /* :any */) {
return Promise.resolve() return Promise.resolve()
} }
} }
// Check if there is another transaction request.
// * the last transaction is always a flush :)
getNextRequest () { getNextRequest () {
if (this.waitingTransactions.length === 0) { if (this.waitingTransactions.length === 0) {
this.transactionInProgress = false if (this.transactionIsFlushed) {
if (this.transactionsFinished != null) { this.transactionInProgress = false
this.transactionsFinished.resolve() this.transactionIsFlushed = false
this.transactionsFinished = null if (this.transactionsFinished != null) {
this.transactionsFinished.resolve()
this.transactionsFinished = null
}
return null
} else {
this.transactionIsFlushed = true
return function * () {
yield* this.flush()
}
} }
return null
} else { } else {
this.transactionIsFlushed = false
return this.waitingTransactions.shift() return this.waitingTransactions.shift()
} }
} }
@ -406,7 +417,7 @@ module.exports = function (Y /* :any */) {
this.waitingTransactions.push(makeGen) this.waitingTransactions.push(makeGen)
if (!this.transactionInProgress) { if (!this.transactionInProgress) {
this.transactionInProgress = true this.transactionInProgress = true
if (true || callImmediately) { // TODO: decide whether this is ok or not.. if (false || callImmediately) { // TODO: decide whether this is ok or not..
this.transact(this.getNextRequest()) this.transact(this.getNextRequest())
} else { } else {
var self = this var self = this

View File

@ -25,7 +25,7 @@ g.g = g
g.YConcurrency_TestingMode = true g.YConcurrency_TestingMode = true
jasmine.DEFAULT_TIMEOUT_INTERVAL = 8000 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++) {

View File

@ -763,6 +763,11 @@ module.exports = function (Y/* :any */) {
return op return op
} }
*/ */
* flush () {
yield* this.os.flush()
yield* this.ss.flush()
yield* this.ds.flush()
}
} }
Y.Transaction = TransactionInterface Y.Transaction = TransactionInterface
} }

View File

@ -207,7 +207,7 @@ module.exports = function (Y /* : any*/) {
Defines a smaller relation on Id's Defines a smaller relation on Id's
*/ */
function smaller (a, b) { function smaller (a, b) {
return a[0] < b[0] || (a[0] === b[0] && a[1] < b[1]) return a[0] < b[0] || (a[0] === b[0] && (a[1] < b[1] || typeof a[1] < typeof b[1]))
} }
Y.utils.smaller = smaller Y.utils.smaller = smaller
@ -249,8 +249,8 @@ module.exports = function (Y /* : any*/) {
I tried to optimize this for performance, therefore no highlevel operations. I tried to optimize this for performance, therefore no highlevel operations.
*/ */
class SmallLookupBuffer extends Store { class SmallLookupBuffer extends Store {
constructor (read, write) { constructor () {
super() super(...arguments)
this.writeBuffer = createEmptyOpsArray(5) this.writeBuffer = createEmptyOpsArray(5)
this.readBuffer = createEmptyOpsArray(10) this.readBuffer = createEmptyOpsArray(10)
} }

View File

@ -110,9 +110,9 @@ class YConfig {
share: {[key: string]: any}; share: {[key: string]: any};
*/ */
constructor (opts, callback) { constructor (opts, callback) {
this.options = opts
this.db = new Y[opts.db.name](this, opts.db) this.db = new Y[opts.db.name](this, opts.db)
this.connector = new Y[opts.connector.name](this, opts.connector) this.connector = new Y[opts.connector.name](this, opts.connector)
this.options = opts
} }
init (callback) { init (callback) {
var opts = this.options var opts = this.options
@ -131,7 +131,8 @@ class YConfig {
} }
share[propertyname] = yield* this.getType(id) share[propertyname] = yield* this.getType(id)
} }
setTimeout(callback, 0) this.store.whenTransactionsFinished()
.then(callback)
}) })
} }
isConnected () { isConnected () {