Create Structs based on offset, if necessary
implement offset parameter in Ref.toStruct
This commit is contained in:
@@ -19,20 +19,20 @@ export class StructStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the states as an array of {client,clock} pairs.
|
||||
* Return the states as a Map<client,clock>.
|
||||
* Note that clock refers to the next expected clock id.
|
||||
*
|
||||
* @param {StructStore} store
|
||||
* @return {Array<{client:number,clock:number}>}
|
||||
* @return {Map<number,number>}
|
||||
*/
|
||||
export const getStates = store =>
|
||||
map.map(store.clients, (structs, client) => {
|
||||
export const getStates = store => {
|
||||
const sm = new Map()
|
||||
store.clients.forEach((structs, client) => {
|
||||
const struct = structs[structs.length - 1]
|
||||
return {
|
||||
client,
|
||||
clock: struct.id.clock + struct.length
|
||||
}
|
||||
sm.set(client, struct.id.clock + struct.length)
|
||||
})
|
||||
return sm
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {StructStore} store
|
||||
|
||||
@@ -56,8 +56,11 @@ export class Transaction {
|
||||
* Holds the state before the transaction started.
|
||||
* @type {Map<Number,Number>}
|
||||
*/
|
||||
this.beforeState = new Map()
|
||||
getStates(y.store).forEach(({client, clock}) => { this.beforeState.set(client, clock) })
|
||||
this.beforeState = getStates(y.store)
|
||||
/**
|
||||
* Holds the state after the transaction.
|
||||
* @type {Map<Number,Number>}
|
||||
*/
|
||||
this.afterState = new Map()
|
||||
/**
|
||||
* All types that were directly modified (property added or child
|
||||
|
||||
@@ -96,9 +96,7 @@ export class Y extends Observable {
|
||||
// only call afterTransaction listeners if anything changed
|
||||
const transactionChangedContent = transaction.changedParentTypes.size !== 0
|
||||
if (transactionChangedContent) {
|
||||
getStates(transaction.y.store).forEach(({client, clock}) => {
|
||||
transaction.afterState.set(client, clock)
|
||||
})
|
||||
transaction.afterState = getStates(transaction.y.store)
|
||||
// when all changes & events are processed, emit afterTransaction event
|
||||
this.emit('afterTransaction', [this, transaction])
|
||||
// transaction cleanup
|
||||
@@ -152,7 +150,8 @@ export class Y extends Observable {
|
||||
// @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--) {
|
||||
const firstChangePos = math.max(findIndexSS(structs, clock), 1)
|
||||
for (let i = structs.length - 1; i >= firstChangePos; i--) {
|
||||
tryToMergeWithLeft(structs, i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,19 +43,23 @@ const structRefs = [
|
||||
* @param {decoding.Decoder} decoder
|
||||
* @param {number} structsLen
|
||||
* @param {ID} nextID
|
||||
* @param {number} localState next expected clock by nextID.client
|
||||
* @return {Iterator<AbstractRef>}
|
||||
*/
|
||||
const createStructReaderIterator = (decoder, structsLen, nextID) => iterator.createIterator(() => {
|
||||
const createStructReaderIterator = (decoder, structsLen, nextID, localState) => iterator.createIterator(() => {
|
||||
let done = false
|
||||
let value
|
||||
if (structsLen === 0) {
|
||||
done = true
|
||||
} else {
|
||||
do {
|
||||
if (structsLen === 0) {
|
||||
done = true
|
||||
value = undefined
|
||||
break
|
||||
}
|
||||
const info = decoding.readUint8(decoder)
|
||||
value = new structRefs[binary.BITS5 & info](decoder, nextID, info)
|
||||
nextID = createID(nextID.client, nextID.clock + value.length)
|
||||
structsLen--
|
||||
}
|
||||
} while (nextID.clock <= localState) // read until we find something new (check nextID.clock instead because it equals `clock+len`)
|
||||
return { done, value }
|
||||
})
|
||||
|
||||
@@ -78,7 +82,7 @@ export const writeStructs = (encoder, store, _sm) => {
|
||||
sm.set(client, clock)
|
||||
}
|
||||
})
|
||||
getStates(store).forEach(({client}) => {
|
||||
getStates(store).forEach((clock, client) => {
|
||||
if (!_sm.has(client)) {
|
||||
sm.set(client, 0)
|
||||
}
|
||||
@@ -131,17 +135,18 @@ export const readStructs = (decoder, transaction, store) => {
|
||||
*/
|
||||
const structReaders = new Map()
|
||||
const clientbeforeState = decoding.readVarUint(decoder)
|
||||
/**
|
||||
* @type {Array<AbstractRef>}
|
||||
*/
|
||||
const stack = []
|
||||
const localState = getStates(store)
|
||||
for (let i = 0; i < clientbeforeState; i++) {
|
||||
const nextID = readID(decoder)
|
||||
const decoderPos = decoder.pos + decoding.readUint32(decoder)
|
||||
const structReaderDecoder = decoding.clone(decoder, decoderPos)
|
||||
const numberOfStructs = decoding.readVarUint(structReaderDecoder)
|
||||
structReaders.set(nextID.client, createStructReaderIterator(structReaderDecoder, numberOfStructs, nextID))
|
||||
structReaders.set(nextID.client, createStructReaderIterator(structReaderDecoder, numberOfStructs, nextID, localState.get(nextID.client) || 0))
|
||||
}
|
||||
/**
|
||||
* @type {Array<AbstractRef>}
|
||||
*/
|
||||
const stack = []
|
||||
for (const it of structReaders.values()) {
|
||||
// todo try for in of it
|
||||
for (let res = it.next(); !res.done; res = it.next()) {
|
||||
@@ -159,7 +164,9 @@ export const readStructs = (decoder, transaction, store) => {
|
||||
ref._missing.pop()
|
||||
}
|
||||
if (m.length === 0) {
|
||||
ref.toStruct(transaction).integrate(transaction)
|
||||
const localClock = (localState.get(ref.id.client) || 0)
|
||||
const offset = ref.id.clock < localClock ? localClock - ref.id.clock : 0
|
||||
ref.toStruct(transaction, offset).integrate(transaction)
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user