after refactor - some tests are working again

This commit is contained in:
Kevin Jahns
2019-04-05 00:37:09 +02:00
parent 30bf3742c9
commit e56899a02c
23 changed files with 234 additions and 152 deletions

View File

@@ -88,6 +88,9 @@ export const findIndexSS = (structs, clock) => {
if (clock < midclock + mid.length) {
return midindex
}
if (left === midindex) {
throw error.unexpectedCase()
}
left = midindex
} else {
right = midindex

View File

@@ -9,6 +9,7 @@ import {
writeDeleteSet,
DeleteSet,
sortAndMergeDeleteSet,
getStates,
AbstractType, AbstractItem, YEvent, ItemType, Y // eslint-disable-line
} from '../internals.js'
@@ -52,12 +53,12 @@ export class Transaction {
*/
this.deleteSet = new DeleteSet()
/**
* If a state was modified, the original value is saved here.
* Use `stateUpdates` to compute the original state before the transaction,
* or to compute the set of inserted operations.
* Holds the state before the transaction started.
* @type {Map<Number,Number>}
*/
this.stateUpdates = new Map()
this.beforeState = new Map()
getStates(y.store).forEach(({client, clock}) => { this.beforeState.set(client, clock) })
this.afterState = new Map()
/**
* All types that were directly modified (property added or child
* inserted/deleted). New types are not included in this Set.

View File

@@ -1,4 +1,4 @@
import { } from './StructStore.js'
import { getStates } from './StructStore.js'
import {
callEventHandlerListeners,
@@ -75,26 +75,29 @@ export class Y extends Observable {
if (initialCall) {
const transaction = this._transaction
this._transaction = null
// only call event listeners / observers if anything changed
this.emit('beforeObserverCalls', [this, this._transaction])
// emit change events on changed types
transaction.changed.forEach((subs, itemtype) => {
itemtype._callObserver(transaction, subs)
})
transaction.changedParentTypes.forEach((events, type) => {
events = events
.filter(event =>
event.target._item === null || !event.target._item.deleted
)
events
.forEach(event => {
event.currentTarget = type
})
// we don't need to check for events.length
// because we know it has at least one element
callEventHandlerListeners(type._dEH, [events, transaction])
})
// only call afterTransaction listeners if anything changed
const transactionChangedContent = transaction.changedParentTypes.size !== 0
if (transactionChangedContent) {
this.emit('beforeObserverCalls', [this, this._transaction])
// emit change events on changed types
transaction.changed.forEach((subs, itemtype) => {
itemtype._callObserver(transaction, subs)
})
transaction.changedParentTypes.forEach((events, type) => {
events = events
.filter(event =>
event.target._item === null || !event.target._item.deleted
)
events
.forEach(event => {
event.currentTarget = type
})
// we don't need to check for events.length
// because we know it has at least one element
callEventHandlerListeners(type._dEH, [events, transaction])
getStates(transaction.y.store).forEach(({client, clock}) => {
transaction.afterState.set(client, clock)
})
// when all changes & events are processed, emit afterTransaction event
this.emit('afterTransaction', [this, transaction])
@@ -141,15 +144,17 @@ export class Y extends Observable {
}
}
// on all affected store.clients props, try to merge
for (const [client, clock] of transaction.stateUpdates) {
/**
* @type {Array<AbstractStruct>}
*/
// @ts-ignore
const structs = store.clients.get(client)
// we iterate from right to left so we can safely remove entries
for (let i = structs.length - 1; i >= math.max(findIndexSS(structs, clock), 1); i--) {
tryToMergeWithLeft(structs, i)
for (const [client, clock] of transaction.beforeState) {
if (transaction.afterState.get(client) !== clock) {
/**
* @type {Array<AbstractStruct>}
*/
// @ts-ignore
const structs = store.clients.get(client)
// we iterate from right to left so we can safely remove entries
for (let i = structs.length - 1; i >= math.max(findIndexSS(structs, clock), 1); i--) {
tryToMergeWithLeft(structs, i)
}
}
}
// try to merge replacedItems
@@ -200,16 +205,21 @@ export class Y extends Observable {
* @return {AbstractType<any>} The created type. Constructed with TypeConstructor
*/
get (name, TypeConstructor = AbstractType) {
// @ts-ignore
const type = map.setIfUndefined(this.share, name, () => new TypeConstructor())
const type = map.setIfUndefined(this.share, name, () => {
// @ts-ignore
const t = new TypeConstructor()
t._integrate(this, null)
return t
})
const Constr = type.constructor
if (Constr !== TypeConstructor) {
if (TypeConstructor !== AbstractType && Constr !== TypeConstructor) {
if (Constr === AbstractType) {
const t = new Constr()
t._map = type._map
t._start = type._start
t._length = type._length
this.share.set(name, t)
t._integrate(this, null)
return t
} else {
throw new Error(`Type with the name ${name} has already been defined with a different constructor`)

View File

@@ -67,7 +67,7 @@ export class YEvent {
* @return {boolean}
*/
adds (struct) {
return struct.id.clock > (this.transaction.stateUpdates.get(struct.id.client) || 0)
return struct.id.clock > (this.transaction.beforeState.get(struct.id.client) || 0)
}
}

View File

@@ -13,6 +13,8 @@ import {
writeID,
createID,
readID,
getState,
getStates,
Transaction, AbstractStruct, AbstractRef, StructStore, ID // eslint-disable-line
} from '../internals.js'
@@ -51,7 +53,8 @@ const createStructReaderIterator = (decoder, structsLen, nextID) => iterator.cre
} else {
const info = decoding.readUint8(decoder)
value = new structRefs[binary.BITS5 & info](decoder, nextID, info)
nextID = createID(nextID.client, nextID.clock)
nextID = createID(nextID.client, nextID.clock + value.length)
structsLen--
}
return { done, value }
})
@@ -60,18 +63,30 @@ const createStructReaderIterator = (decoder, structsLen, nextID) => iterator.cre
* @param {encoding.Encoder} encoder
* @param {Transaction} transaction
*/
export const writeStructsFromTransaction = (encoder, transaction) => writeStructs(encoder, transaction.y.store, transaction.stateUpdates)
export const writeStructsFromTransaction = (encoder, transaction) => writeStructs(encoder, transaction.y.store, transaction.beforeState)
/**
* @param {encoding.Encoder} encoder
* @param {StructStore} store
* @param {StateMap} sm
* @param {StateMap} _sm
*/
export const writeStructs = (encoder, store, sm) => {
export const writeStructs = (encoder, store, _sm) => {
// we filter all valid _sm entries into sm
const sm = new Map()
_sm.forEach((clock, client) => {
if (getState(store, client) > clock) {
sm.set(client, clock)
}
})
getStates(store).forEach(({client}) => {
if (!_sm.has(client)) {
sm.set(client, 0)
}
})
const encoderUserPosMap = map.create()
// write # states that were updated
encoding.writeVarUint(encoder, sm.size)
sm.forEach((client, clock) => {
sm.forEach((clock, client) => {
// write first id
writeID(encoder, createID(client, clock))
encoderUserPosMap.set(client, encoding.length(encoder))
@@ -79,7 +94,7 @@ export const writeStructs = (encoder, store, sm) => {
// We will fill out this value later *)
encoding.writeUint32(encoder, 0)
})
sm.forEach((client, clock) => {
sm.forEach((clock, client) => {
const decPos = encoderUserPosMap.get(client)
encoding.setUint32(encoder, decPos, encoding.length(encoder) - decPos)
/**
@@ -115,8 +130,8 @@ export const readStructs = (decoder, transaction, store) => {
* @type {Map<number,Iterator<AbstractRef>>}
*/
const structReaders = new Map()
const clientStateUpdates = decoding.readVarUint(decoder)
for (let i = 0; i < clientStateUpdates; i++) {
const clientbeforeState = decoding.readVarUint(decoder)
for (let i = 0; i < clientbeforeState; i++) {
const nextID = readID(decoder)
const decoderPos = decoder.pos + decoding.readUint32(decoder)
const structReaderDecoder = decoding.clone(decoder, decoderPos)