Use deterministic ids based on a seed

This commit is contained in:
James Allen 2017-01-09 10:49:03 +01:00
parent cb24e9390a
commit ae30f32481
6 changed files with 47 additions and 26 deletions

View file

@ -83,6 +83,9 @@ define [
setTrackingChanges: (track_changes) ->
@doc.track_changes = track_changes
setTrackChangesIdSeeds: (id_seeds) ->
@doc.track_changes_id_seeds = id_seeds
_bindToSocketEvents: () ->
@_onUpdateAppliedHandler = (update) => @_onUpdateApplied(update)
@ -319,6 +322,8 @@ define [
v: version
@doc.on "change", (ops, oldSnapshot, msg) =>
@_applyOpsToRanges(ops, oldSnapshot, msg)
@doc.on "flipped_pending_to_inflight", () =>
@trigger "flipped_pending_to_inflight"
_onError: (error, meta = {}) ->
meta.doc_id = @doc_id
@ -335,6 +340,8 @@ define [
_applyOpsToRanges: (ops = [], oldSnapshot, msg) ->
track_changes_as = null
remote_op = msg?
if msg.meta?.tc?
@ranges.setIdSeed(msg.meta.tc)
if remote_op and msg.meta?.tc
track_changes_as = msg.meta.user_id
else if !remote_op and @track_changes_as?

View file

@ -166,14 +166,11 @@ define [
if want == have
return
console.log "Trying to set track changes to:", want
do tryToggle = () =>
saved = !doc.getInflightOp()? and !doc.getPendingOp()?
if saved
console.log "SUCCESS, changing value", want
doc.setTrackingChanges(want)
@$scope.$apply () =>
@$scope.editor.trackChanges = want
else
console.log "Still in flight, will try soon"
@_syncTimeout = setTimeout tryToggle, 100

View file

@ -24,7 +24,7 @@ define [
return
if @track_changes
update.meta ?= {}
update.meta.tc = 1
update.meta.tc = @track_changes_id_seeds.inflight
@socket.emit "applyOtUpdate", @doc_id, update, (error) =>
return @_handleError(error) if error?
state: "ok"
@ -44,6 +44,8 @@ define [
# ops as quickly as possible for low latency.
@_doc.setFlushDelay(0)
@trigger "remoteop", args...
@_doc.on "flipped_pending_to_inflight", () =>
@trigger "flipped_pending_to_inflight"
@_doc.on "error", (e) =>
@_handleError(e)
@ -117,7 +119,7 @@ define [
attachToAce: (ace) -> @_doc.attach_ace(ace, false, window.maxDocLength)
detachFromAce: () -> @_doc.detach_ace?()
INFLIGHT_OP_TIMEOUT: 5000 # Retry sending ops after 5 seconds without an ack
WAIT_FOR_CONNECTION_TIMEOUT: 500 # If we're waiting for the project to join, try again in 0.5 seconds
_startInflightOpTimeout: (update) ->

View file

@ -266,6 +266,8 @@ class Doc
@pendingOp = null
@pendingCallbacks = []
@emit "flipped_pending_to_inflight"
#console.log "SENDING OP TO SERVER", @inflightOp, @version
@connection.send {doc:@name, op:@inflightOp, v:@version}

View file

@ -36,24 +36,18 @@ load = (EventEmitter) ->
# middle of a previous insert by the first user, the original insert will be split into two.
constructor: (@changes = [], @comments = []) ->
@_increment: 0
@newId: () ->
# Generate a Mongo ObjectId
# Reference: https://github.com/dreampulse/ObjectId.js/blob/master/src/main/javascript/Objectid.js
@_pid ?= Math.floor(Math.random() * (32767))
@_machine ?= Math.floor(Math.random() * (16777216))
timestamp = Math.floor(new Date().valueOf() / 1000)
@_increment++
timestamp = timestamp.toString(16)
machine = @_machine.toString(16)
pid = @_pid.toString(16)
increment = @_increment.toString(16)
return '00000000'.substr(0, 8 - timestamp.length) + timestamp +
'000000'.substr(0, 6 - machine.length) + machine +
'0000'.substr(0, 4 - pid.length) + pid +
'000000'.substr(0, 6 - increment.length) + increment;
getIdSeed: () ->
return @id_seed
setIdSeed: (seed) ->
@id_seed = seed
@id_increment = 0
newId: () ->
@id_increment++
increment = @id_increment.toString(16)
id = @id_seed + '000000'.substr(0, 6 - increment.length) + increment;
return id
getComment: (comment_id) ->
comment = null
@ -99,7 +93,7 @@ load = (EventEmitter) ->
addComment: (op, metadata) ->
# TODO: Don't allow overlapping comments?
@comments.push comment = {
id: RangesTracker.newId()
id: @newId()
op: # Copy because we'll modify in place
c: op.c
p: op.p
@ -390,7 +384,7 @@ load = (EventEmitter) ->
_addOp: (op, metadata) ->
change = {
id: RangesTracker.newId()
id: @newId()
op: op
metadata: metadata
}

View file

@ -75,12 +75,17 @@ define [
if view == $scope.SubViews.OVERVIEW
refreshOverviewPanel()
$scope.$watch "editor.sharejs_doc", (doc) ->
$scope.$watch "editor.sharejs_doc", (doc, old_doc) ->
return if !doc?
# The open doc range tracker is kept up to date in real-time so
# replace any outdated info with this
rangesTrackers[doc.doc_id] = doc.ranges
$scope.reviewPanel.rangesTracker = rangesTrackers[doc.doc_id]
if old_doc?
old_doc.off "flipped_pending_to_inflight"
doc.on "flipped_pending_to_inflight", () ->
regenerateTrackChangesId(doc)
regenerateTrackChangesId(doc)
$scope.$watch (() ->
entries = $scope.reviewPanel.entries[$scope.editor.open_doc_id] or {}
@ -94,6 +99,20 @@ define [
$scope.$broadcast "review-panel:toggle"
$scope.$broadcast "review-panel:layout"
regenerateTrackChangesId = (doc) ->
old_id = getChangeTracker(doc.doc_id).getIdSeed()
# Generate a the first 18 characters of Mongo ObjectId, leaving 6 for the increment part
# Reference: https://github.com/dreampulse/ObjectId.js/blob/master/src/main/javascript/Objectid.js
pid = Math.floor(Math.random() * (32767)).toString(16)
machine = Math.floor(Math.random() * (16777216)).toString(16)
timestamp = Math.floor(new Date().valueOf() / 1000).toString(16)
new_id = '00000000'.substr(0, 8 - timestamp.length) + timestamp +
'000000'.substr(0, 6 - machine.length) + machine +
'0000'.substr(0, 4 - pid.length) + pid
getChangeTracker(doc.doc_id).setIdSeed(new_id)
doc.setTrackChangesIdSeeds({pending: new_id, inflight: old_id})
refreshOverviewPanel = () ->
$scope.reviewPanel.overview.loading = true
$http.get "/project/#{$scope.project_id}/ranges"