@@ -881,29 +881,38 @@ Backend.prototype._fetchSnapshotByTimestamp = function(collection, id, timestamp
881881 var from = 0 ;
882882 var to = null ;
883883
884- var shouldGetLatestSnapshot = timestamp === null ;
885- if ( shouldGetLatestSnapshot ) {
886- return backend . db . getSnapshot ( collection , id , null , null , function ( error , snapshot ) {
887- if ( error ) return callback ( error ) ;
888-
889- callback ( null , snapshot ) ;
890- } ) ;
891- }
892-
893- milestoneDb . getMilestoneSnapshotAtOrBeforeTime ( collection , id , timestamp , function ( error , snapshot ) {
884+ // Always fetch the current snapshot first. We request its metadata so that we
885+ // can read its mtime, which lets us serve the current snapshot directly when
886+ // the requested timestamp is after it. This avoids replaying ops when they
887+ // aren't needed, and - crucially - still works when older ops have been
888+ // deleted/TTLed and the current version can no longer be rebuilt from ops.
889+ db . getSnapshot ( collection , id , null , { metadata : true } , function ( error , currentSnapshot ) {
894890 if ( error ) return callback ( error ) ;
895- milestoneSnapshot = snapshot ;
896- if ( snapshot ) from = snapshot . v ;
897891
898- milestoneDb . getMilestoneSnapshotAtOrAfterTime ( collection , id , timestamp , function ( error , snapshot ) {
892+ var mtime = currentSnapshot . m && currentSnapshot . m . mtime ;
893+ var shouldGetLatestSnapshot = timestamp === null || ( mtime != null && timestamp > mtime ) ;
894+ if ( shouldGetLatestSnapshot ) {
895+ // Strip the metadata that we only fetched in order to compare the mtime,
896+ // so that the returned snapshot is consistent with the op-replayed path.
897+ currentSnapshot . m = null ;
898+ return callback ( null , currentSnapshot ) ;
899+ }
900+
901+ milestoneDb . getMilestoneSnapshotAtOrBeforeTime ( collection , id , timestamp , function ( error , snapshot ) {
899902 if ( error ) return callback ( error ) ;
900- if ( snapshot ) to = snapshot . v ;
903+ milestoneSnapshot = snapshot ;
904+ if ( snapshot ) from = snapshot . v ;
901905
902- var options = { metadata : true } ;
903- db . getOps ( collection , id , from , to , options , function ( error , ops ) {
906+ milestoneDb . getMilestoneSnapshotAtOrAfterTime ( collection , id , timestamp , function ( error , snapshot ) {
904907 if ( error ) return callback ( error ) ;
905- filterOpsInPlaceBeforeTimestamp ( ops , timestamp ) ;
906- backend . _buildSnapshotFromOps ( id , milestoneSnapshot , ops , callback ) ;
908+ if ( snapshot ) to = snapshot . v ;
909+
910+ var options = { metadata : true } ;
911+ db . getOps ( collection , id , from , to , options , function ( error , ops ) {
912+ if ( error ) return callback ( error ) ;
913+ filterOpsInPlaceBeforeTimestamp ( ops , timestamp ) ;
914+ backend . _buildSnapshotFromOps ( id , milestoneSnapshot , ops , callback ) ;
915+ } ) ;
907916 } ) ;
908917 } ) ;
909918 } ) ;
0 commit comments