Skip to content

Commit

Permalink
Simplify shouldBreak calls for fetching snapshots by timestamp
Browse files Browse the repository at this point in the history
This change removes or renames `shouldBreak` calls. In `Backend`, for
clarity we instead pre-filter ops, and just pass around the ops we want
to be applied to a snapshot.

In the `MemoryMilestoneDB`, these functions are extracted and renamed to
more descriptive break condition names.
  • Loading branch information
Alec Gibson committed Dec 19, 2018
1 parent 4a7a178 commit dc9b8ca
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 51 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -485,5 +485,5 @@ The `41xx` and `51xx` codes are reserved for use by ShareDB DB adapters, and the
* 5018 - Required QueryEmitter listener not assigned
* 5019 - getMilestoneSnapshot MilestoneDB method unimplemented
* 5020 - saveMilestoneSnapshot MilestoneDB method unimplemented
* 5021 - getMilestoneSnapshotBeforeTime MilestoneDB method unimplemented
* 5022 - getMilestoneSnapshotAfterTime MilestoneDB method unimplemented
* 5021 - getMilestoneSnapshotAtOrBeforeTime MilestoneDB method unimplemented
* 5022 - getMilestoneSnapshotAtOrAfterTime MilestoneDB method unimplemented
33 changes: 18 additions & 15 deletions lib/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -701,22 +701,14 @@ Backend.prototype._fetchSnapshotByTimestamp = function (collection, id, timestam
var options = {metadata: true};
db.getOps(collection, id, from, to, options, function (error, ops) {
if (error) return callback(error);
backend._buildSnapshotFromOps(id, milestoneSnapshot, ops, callback, function shouldBreak(nextOp) {
var opTimestamp = nextOp && nextOp.m && nextOp.m.ts;
return timestamp !== null && opTimestamp > timestamp;
});
filterOpsInPlaceBeforeTimestamp(ops, timestamp);
backend._buildSnapshotFromOps(id, milestoneSnapshot, ops, callback);
});
});
});
};

Backend.prototype._buildSnapshotFromOps = function (id, startingSnapshot, ops, callback, shouldBreak) {
if (typeof shouldBreak !== 'function') {
shouldBreak = function () {
return false;
};
}

Backend.prototype._buildSnapshotFromOps = function (id, startingSnapshot, ops, callback) {
var type = null;
var data;
var fetchedVersion = 0;
Expand All @@ -731,10 +723,6 @@ Backend.prototype._buildSnapshotFromOps = function (id, startingSnapshot, ops, c
for (var index = 0; index < ops.length; index++) {
var op = ops[index];

if (shouldBreak(op)) {
break;
}

fetchedVersion = op.v + 1;

if (op.create) {
Expand Down Expand Up @@ -762,3 +750,18 @@ function pluckIds(snapshots) {
}
return ids;
}

function filterOpsInPlaceBeforeTimestamp(ops, timestamp) {
if (timestamp === null) {
return;
}

for (var i = 0; i < ops.length; i++) {
var op = ops[i];
var opTimestamp = op.m && op.m.ts;
if (opTimestamp > timestamp) {
ops.length = i;
return;
}
}
}
2 changes: 1 addition & 1 deletion lib/client/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ Connection.prototype.fetchSnapshot = function(collection, id, version, callback)
};

/**
* Fetch a read-only snapshot at a given version
* Fetch a read-only snapshot at a given timestamp
*
* @param collection - the collection name of the snapshot
* @param id - the ID of the snapshot
Expand Down
4 changes: 2 additions & 2 deletions lib/milestone-db/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ MilestoneDB.prototype.saveMilestoneSnapshot = function (collection, snapshot, ca
};

MilestoneDB.prototype.getMilestoneSnapshotAtOrBeforeTime = function (collection, id, timestamp, callback) {
var error = new ShareDBError(5021, 'getMilestoneSnapshotBeforeTime MilestoneDB method unimplemented');
var error = new ShareDBError(5021, 'getMilestoneSnapshotAtOrBeforeTime MilestoneDB method unimplemented');
this._callBackOrEmitError(error, callback);
};

MilestoneDB.prototype.getMilestoneSnapshotAtOrAfterTime = function (collection, id, timestamp, callback) {
var error = new ShareDBError(5022, 'getMilestoneSnapshotAfterTime MilestoneDB method unimplemented');
var error = new ShareDBError(5022, 'getMilestoneSnapshotAtOrAfterTime MilestoneDB method unimplemented');
this._callBackOrEmitError(error, callback);
};

Expand Down
72 changes: 41 additions & 31 deletions lib/milestone-db/memory.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,8 @@ MemoryMilestoneDB.prototype = Object.create(MilestoneDB.prototype);
MemoryMilestoneDB.prototype.getMilestoneSnapshot = function (collection, id, version, callback) {
if (!this._isValidVersion(version)) return process.nextTick(callback, new ShareDBError(4001, 'Invalid version'));

var shouldBreak = function (currentSnapshot, nextSnapshot) {
if (version === null) {
return false;
}

return nextSnapshot.v > version;
};

this._findMilestoneSnapshot(collection, id, shouldBreak, callback);
var predicate = versionLessThanOrEqualTo(version);
this._findMilestoneSnapshot(collection, id, predicate, callback);
};

MemoryMilestoneDB.prototype.saveMilestoneSnapshot = function (collection, snapshot, callback) {
Expand All @@ -57,31 +50,15 @@ MemoryMilestoneDB.prototype.saveMilestoneSnapshot = function (collection, snapsh
MemoryMilestoneDB.prototype.getMilestoneSnapshotAtOrBeforeTime = function (collection, id, timestamp, callback) {
if (!this._isValidTimestamp(timestamp)) return process.nextTick(callback, new ShareDBError(4001, 'Invalid timestamp'));

var shouldBreak = function (currentSnapshot, nextSnapshot) {
if (timestamp === null) {
return !!currentSnapshot;
}

var mtime = nextSnapshot && nextSnapshot.m && nextSnapshot.m.mtime;
return mtime > timestamp;
};

this._findMilestoneSnapshot(collection, id, shouldBreak, callback);
var filter = timestampLessThanOrEqualTo(timestamp);
this._findMilestoneSnapshot(collection, id, filter, callback);
};

MemoryMilestoneDB.prototype.getMilestoneSnapshotAtOrAfterTime = function (collection, id, timestamp, callback) {
if (!this._isValidTimestamp(timestamp)) return process.nextTick(callback, new ShareDBError(4001, 'Invalid timestamp'));

var shouldBreak = function (currentSnapshot) {
if (timestamp === null) {
return false;
}

var mtime = currentSnapshot && currentSnapshot.m && currentSnapshot.m.mtime;
return mtime >= timestamp;
}

this._findMilestoneSnapshot(collection, id, shouldBreak, function (error, snapshot) {
var filter = timestampGreaterThanOrEqualTo(timestamp);
this._findMilestoneSnapshot(collection, id, filter, function (error, snapshot) {
if (error) return process.nextTick(callback, error);

var mtime = snapshot && snapshot.m && snapshot.m.mtime;
Expand All @@ -93,7 +70,8 @@ MemoryMilestoneDB.prototype.getMilestoneSnapshotAtOrAfterTime = function (collec
});
};

MemoryMilestoneDB.prototype._findMilestoneSnapshot = function (collection, id, shouldBreak, callback) {
// TODO: Rename shouldBreak to something like breakCondition
MemoryMilestoneDB.prototype._findMilestoneSnapshot = function (collection, id, breakCondition, callback) {
if (!collection) return process.nextTick(callback, new ShareDBError(4001, 'Missing collection'));
if (!id) return process.nextTick(callback, new ShareDBError(4001, 'Missing ID'));

Expand All @@ -102,7 +80,7 @@ MemoryMilestoneDB.prototype._findMilestoneSnapshot = function (collection, id, s
var milestoneSnapshot;
for (var i = 0; i < milestoneSnapshots.length; i++) {
var nextMilestoneSnapshot = milestoneSnapshots[i];
if (shouldBreak(milestoneSnapshot, nextMilestoneSnapshot)) {
if (breakCondition(milestoneSnapshot, nextMilestoneSnapshot)) {
break;
} else {
milestoneSnapshot = nextMilestoneSnapshot;
Expand All @@ -116,3 +94,35 @@ MemoryMilestoneDB.prototype._getMilestoneSnapshotsSync = function (collection, i
var collectionSnapshots = this._milestoneSnapshots[collection] || (this._milestoneSnapshots[collection] = {});
return collectionSnapshots[id] || (collectionSnapshots[id] = []);
};

function versionLessThanOrEqualTo(version) {
return function (currentSnapshot, nextSnapshot) {
if (version === null) {
return false;
}

return nextSnapshot.v > version;
};
}

function timestampGreaterThanOrEqualTo(timestamp) {
return function (currentSnapshot) {
if (timestamp === null) {
return false;
}

var mtime = currentSnapshot && currentSnapshot.m && currentSnapshot.m.mtime;
return mtime >= timestamp;
};
}

function timestampLessThanOrEqualTo(timestamp) {
return function (currentSnapshot, nextSnapshot) {
if (timestamp === null) {
return !!currentSnapshot;
}

var mtime = nextSnapshot && nextSnapshot.m && nextSnapshot.m.mtime;
return mtime > timestamp;
};
}

0 comments on commit dc9b8ca

Please sign in to comment.