make pollSavedStatus more robust against failure

check last ack timestamp and size of pending op

provide method to compute sharejs op size so we can check if pending
ops get too big
This commit is contained in:
Brian Gough 2016-11-01 16:55:28 +00:00
parent 4623f3cbe7
commit 62b8c30d0b
2 changed files with 36 additions and 4 deletions

View file

@ -69,6 +69,12 @@ define [
getPendingOp: () -> getPendingOp: () ->
@doc?.getPendingOp() @doc?.getPendingOp()
getRecentAck: () ->
@doc?.getRecentAck()
getOpSize: (op) ->
@doc?.getOpSize(op)
hasBufferedOps: () -> hasBufferedOps: () ->
@doc?.hasBufferedOps() @doc?.hasBufferedOps()
@ -143,24 +149,35 @@ define [
clearChaosMonkey: () -> clearChaosMonkey: () ->
clearTimeout @_cm clearTimeout @_cm
MAX_PENDING_OP_SIZE: 30 # pending ops bigger than this are always
# considered unsaved
pollSavedStatus: () -> pollSavedStatus: () ->
# returns false if doc has ops waiting to be acknowledged or # returns false if doc has ops waiting to be acknowledged or
# sent that haven't changed since the last time we checked. # sent that haven't changed since the last time we checked.
# Otherwise returns true. # Otherwise returns true.
inflightOp = @getInflightOp() inflightOp = @getInflightOp()
pendingOp = @getPendingOp() pendingOp = @getPendingOp()
recentAck = @getRecentAck()
pendingOpSize = pendingOp? && @getOpSize(pendingOp)
if !inflightOp? and !pendingOp? if !inflightOp? and !pendingOp?
# there's nothing going on # there's nothing going on, this is ok.
saved = true saved = true
sl_console.log "[pollSavedStatus] no inflight or pending ops" sl_console.log "[pollSavedStatus] no inflight or pending ops"
else if inflightOp? and inflightOp == @oldInflightOp else if inflightOp? and inflightOp == @oldInflightOp
# The same inflight op has been sitting unacked since we # The same inflight op has been sitting unacked since we
# last checked. # last checked, this is bad.
saved = false saved = false
sl_console.log "[pollSavedStatus] inflight op is same as before" sl_console.log "[pollSavedStatus] inflight op is same as before"
else else if pendingOp? and recentAck && pendingOpSize < @MAX_PENDING_OP_SIZE
# There is an op waiting to go to server but it is small and
# within the flushDelay, this is ok for now.
saved = true saved = true
sl_console.log "[pollSavedStatus] assuming saved (inflightOp?: #{inflightOp?}, pendingOp?: #{pendingOp?})" sl_console.log "[pollSavedStatus] pending op (small with recent ack) assume ok", pendingOp, pendingOpSize
else
# In any other situation, assume the document is unsaved.
saved = false
sl_console.log "[pollSavedStatus] assuming not saved (inflightOp?: #{inflightOp?}, pendingOp?: #{pendingOp?})"
@oldInflightOp = inflightOp @oldInflightOp = inflightOp
return saved return saved

View file

@ -46,6 +46,7 @@ define [
@_doc.on "change", () => @_doc.on "change", () =>
@trigger "change" @trigger "change"
@_doc.on "acknowledge", () => @_doc.on "acknowledge", () =>
@lastAcked = new Date() # note time of last ack from server
@trigger "acknowledge" @trigger "acknowledge"
@_doc.on "remoteop", () => @_doc.on "remoteop", () =>
# As soon as we're working with a collaborator, start sending # As soon as we're working with a collaborator, start sending
@ -101,12 +102,26 @@ define [
@connection.id = @socket.socket.sessionid @connection.id = @socket.socket.sessionid
@_doc.autoOpen = false @_doc.autoOpen = false
@_doc._connectionStateChanged(state) @_doc._connectionStateChanged(state)
@lastAcked = null # reset the last ack time when connection changes
hasBufferedOps: () -> hasBufferedOps: () ->
@_doc.inflightOp? or @_doc.pendingOp? @_doc.inflightOp? or @_doc.pendingOp?
getInflightOp: () -> @_doc.inflightOp getInflightOp: () -> @_doc.inflightOp
getPendingOp: () -> @_doc.pendingOp getPendingOp: () -> @_doc.pendingOp
getRecentAck: () ->
# check if we have received an ack recently (within the flush delay)
@lastAcked? and new Date() - @lastAcked < @_doc._flushDelay
getOpSize: (op) ->
# compute size of an op from its components
# (total number of characters inserted and deleted)
size = 0
for component in op or []
if component?.i?
size += component.i.length
if component?.d?
size += component.d.length
return size
attachToAce: (ace) -> @_doc.attach_ace(ace, false, window.maxDocLength) attachToAce: (ace) -> @_doc.attach_ace(ace, false, window.maxDocLength)
detachFromAce: () -> @_doc.detach_ace?() detachFromAce: () -> @_doc.detach_ace?()