improve memory allocation ⇒ less "minor gc" cleanups
This commit is contained in:
@@ -19,15 +19,15 @@ import {
|
||||
GCRef,
|
||||
ItemRef,
|
||||
writeID,
|
||||
createID,
|
||||
readID,
|
||||
getState,
|
||||
createID,
|
||||
getStateVector,
|
||||
readAndApplyDeleteSet,
|
||||
writeDeleteSet,
|
||||
createDeleteSetFromStructStore,
|
||||
transact,
|
||||
Doc, Transaction, AbstractStruct, StructStore, ID // eslint-disable-line
|
||||
Doc, Transaction, GC, Item, StructStore, ID // eslint-disable-line
|
||||
} from '../internals.js'
|
||||
|
||||
import * as encoding from 'lib0/encoding.js'
|
||||
@@ -36,7 +36,7 @@ import * as binary from 'lib0/binary.js'
|
||||
|
||||
/**
|
||||
* @param {encoding.Encoder} encoder
|
||||
* @param {Array<AbstractStruct>} structs All structs by `client`
|
||||
* @param {Array<GC|Item>} structs All structs by `client`
|
||||
* @param {number} client
|
||||
* @param {number} clock write structs starting with `ID(client,clock)`
|
||||
*
|
||||
@@ -50,35 +50,12 @@ const writeStructs = (encoder, structs, client, clock) => {
|
||||
writeID(encoder, createID(client, clock))
|
||||
const firstStruct = structs[startNewStructs]
|
||||
// write first struct with an offset
|
||||
firstStruct.write(encoder, clock - firstStruct.id.clock, 0)
|
||||
firstStruct.write(encoder, clock - firstStruct.id.clock)
|
||||
for (let i = startNewStructs + 1; i < structs.length; i++) {
|
||||
structs[i].write(encoder, 0, 0)
|
||||
structs[i].write(encoder, 0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {decoding.Decoder} decoder
|
||||
* @param {number} numOfStructs
|
||||
* @param {ID} nextID
|
||||
* @return {Array<GCRef|ItemRef>}
|
||||
*
|
||||
* @private
|
||||
* @function
|
||||
*/
|
||||
const readStructRefs = (decoder, numOfStructs, nextID) => {
|
||||
/**
|
||||
* @type {Array<GCRef|ItemRef>}
|
||||
*/
|
||||
const refs = []
|
||||
for (let i = 0; i < numOfStructs; i++) {
|
||||
const info = decoding.readUint8(decoder)
|
||||
const ref = (binary.BITS5 & info) === 0 ? new GCRef(decoder, nextID, info) : new ItemRef(decoder, nextID, info)
|
||||
nextID = createID(nextID.client, nextID.clock + ref.length)
|
||||
refs.push(ref)
|
||||
}
|
||||
return refs
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {encoding.Encoder} encoder
|
||||
* @param {StructStore} store
|
||||
@@ -111,22 +88,30 @@ export const writeClientsStructs = (encoder, store, _sm) => {
|
||||
|
||||
/**
|
||||
* @param {decoding.Decoder} decoder The decoder object to read data from.
|
||||
* @param {Map<number,Array<GCRef|ItemRef>>} clientRefs
|
||||
* @return {Map<number,Array<GCRef|ItemRef>>}
|
||||
*
|
||||
* @private
|
||||
* @function
|
||||
*/
|
||||
export const readClientsStructRefs = decoder => {
|
||||
/**
|
||||
* @type {Map<number,Array<GCRef|ItemRef>>}
|
||||
*/
|
||||
const clientRefs = new Map()
|
||||
export const readClientsStructRefs = (decoder, clientRefs) => {
|
||||
const numOfStateUpdates = decoding.readVarUint(decoder)
|
||||
for (let i = 0; i < numOfStateUpdates; i++) {
|
||||
const numberOfStructs = decoding.readVarUint(decoder)
|
||||
const nextID = readID(decoder)
|
||||
const refs = readStructRefs(decoder, numberOfStructs, nextID)
|
||||
clientRefs.set(nextID.client, refs)
|
||||
const nextIdClient = nextID.client
|
||||
let nextIdClock = nextID.clock
|
||||
/**
|
||||
* @type {Array<GCRef|ItemRef>}
|
||||
*/
|
||||
const refs = []
|
||||
clientRefs.set(nextIdClient, refs)
|
||||
for (let i = 0; i < numberOfStructs; i++) {
|
||||
const info = decoding.readUint8(decoder)
|
||||
const ref = (binary.BITS5 & info) === 0 ? new GCRef(decoder, createID(nextIdClient, nextIdClock), info) : new ItemRef(decoder, createID(nextIdClient, nextIdClock), info)
|
||||
refs.push(ref)
|
||||
nextIdClock += ref.length
|
||||
}
|
||||
}
|
||||
return clientRefs
|
||||
}
|
||||
@@ -171,16 +156,18 @@ const resumeStructIntegration = (transaction, store) => {
|
||||
}
|
||||
const ref = stack[stack.length - 1]
|
||||
const m = ref._missing
|
||||
const client = ref.id.client
|
||||
const refID = ref.id
|
||||
const client = refID.client
|
||||
const refClock = refID.clock
|
||||
const localClock = getState(store, client)
|
||||
const offset = ref.id.clock < localClock ? localClock - ref.id.clock : 0
|
||||
if (ref.id.clock + offset !== localClock) {
|
||||
const offset = refClock < localClock ? localClock - refClock : 0
|
||||
if (refClock + offset !== localClock) {
|
||||
// A previous message from this client is missing
|
||||
// check if there is a pending structRef with a smaller clock and switch them
|
||||
const structRefs = clientsStructRefs.get(client)
|
||||
if (structRefs !== undefined) {
|
||||
const r = structRefs.refs[structRefs.i]
|
||||
if (r.id.clock < ref.id.clock) {
|
||||
if (r.id.clock < refClock) {
|
||||
// put ref with smaller clock on stack instead and continue
|
||||
structRefs.refs[structRefs.i] = ref
|
||||
stack[stack.length - 1] = r
|
||||
@@ -282,7 +269,8 @@ const mergeReadStructsIntoPendingReads = (store, clientsStructsRefs) => {
|
||||
* @function
|
||||
*/
|
||||
export const readStructs = (decoder, transaction, store) => {
|
||||
const clientsStructRefs = readClientsStructRefs(decoder)
|
||||
const clientsStructRefs = new Map()
|
||||
readClientsStructRefs(decoder, clientsStructRefs)
|
||||
mergeReadStructsIntoPendingReads(store, clientsStructRefs)
|
||||
resumeStructIntegration(transaction, store)
|
||||
tryResumePendingDeleteReaders(transaction, store)
|
||||
|
||||
Reference in New Issue
Block a user