@@ -28,6 +28,7 @@ import { MongoBucketBatch } from './MongoBucketBatch.js';
28
28
import { MongoCompactor } from './MongoCompactor.js' ;
29
29
import { MongoWriteCheckpointAPI } from './MongoWriteCheckpointAPI.js' ;
30
30
import { idPrefixFilter , mapOpEntry , readSingleBatch } from './util.js' ;
31
+ import { LRUCache } from 'lru-cache' ;
31
32
32
33
export class MongoSyncBucketStorage
33
34
extends DisposableObserver < storage . SyncRulesBucketStorageListener >
@@ -849,25 +850,40 @@ export class MongoSyncBucketStorage
849
850
return pipeline ;
850
851
}
851
852
852
- async getCheckpointChanges ( options : GetCheckpointChangesOptions ) : Promise < CheckpointChanges > {
853
- const dataBuckets = await this . db . bucket_data
854
- . find (
855
- {
856
- '_id.g' : this . group_id ,
857
- '_id.o' : { $gt : BigInt ( options . lastCheckpoint ) , $lte : BigInt ( options . nextCheckpoint ) }
858
- } ,
859
- {
860
- projection : {
861
- '_id.b' : 1
862
- } ,
863
- limit : 1001 ,
864
- batchSize : 1001 ,
865
- singleBatch : true
866
- }
867
- )
868
- . toArray ( ) ;
869
- const invalidateDataBuckets = dataBuckets . length > 1000 ;
853
+ private async getDataBucketChanges (
854
+ options : GetCheckpointChangesOptions
855
+ ) : Promise < Pick < CheckpointChanges , 'updatedDataBuckets' | 'invalidateDataBuckets' > > {
856
+ // The query below can be slow, since we don't have an index on _id.o.
857
+ // We could try to query the oplog for these, but that is risky.
858
+ // Or we could store updated buckets in a separate collection, and query those.
859
+ // For now, we ignore this optimization
860
+
861
+ // const dataBuckets = await this.db.bucket_data
862
+ // .find(
863
+ // {
864
+ // '_id.g': this.group_id,
865
+ // '_id.o': { $gt: BigInt(options.lastCheckpoint), $lte: BigInt(options.nextCheckpoint) }
866
+ // },
867
+ // {
868
+ // projection: {
869
+ // '_id.b': 1
870
+ // },
871
+ // limit: 1001,
872
+ // batchSize: 1001,
873
+ // singleBatch: true
874
+ // }
875
+ // )
876
+ // .toArray();
877
+
878
+ return {
879
+ invalidateDataBuckets : true ,
880
+ updatedDataBuckets : [ ]
881
+ } ;
882
+ }
870
883
884
+ private async getParameterBucketChanges (
885
+ options : GetCheckpointChangesOptions
886
+ ) : Promise < Pick < CheckpointChanges , 'updatedParameterBucketDefinitions' | 'invalidateParameterBuckets' > > {
871
887
const parameterUpdates = await this . db . bucket_parameters
872
888
. find (
873
889
{
@@ -887,13 +903,37 @@ export class MongoSyncBucketStorage
887
903
const invalidateParameterUpdates = parameterUpdates . length > 1000 ;
888
904
889
905
return {
890
- invalidateDataBuckets,
891
- updatedDataBuckets : invalidateDataBuckets ? [ ] : dataBuckets . map ( ( b ) => b . _id . b ) ,
892
-
893
906
invalidateParameterBuckets : invalidateParameterUpdates ,
894
907
updatedParameterBucketDefinitions : invalidateParameterUpdates
895
908
? [ ]
896
909
: [ ...new Set < string > ( parameterUpdates . map ( ( p ) => getLookupBucketDefinitionName ( p . lookup ) ) ) ]
897
910
} ;
898
911
}
912
+
913
+ private checkpointChangesCache = new LRUCache < string , CheckpointChanges , { options : GetCheckpointChangesOptions } > ( {
914
+ max : 50 ,
915
+ maxSize : 10 * 1024 * 1024 ,
916
+ sizeCalculation : ( value : CheckpointChanges ) => {
917
+ return value . updatedParameterBucketDefinitions . reduce < number > ( ( a , b ) => a + b . length , 0 ) ;
918
+ } ,
919
+ fetchMethod : async ( _key , _staleValue , options ) => {
920
+ return this . getCheckpointChangesInternal ( options . context . options ) ;
921
+ }
922
+ } ) ;
923
+
924
+ async getCheckpointChanges ( options : GetCheckpointChangesOptions ) : Promise < CheckpointChanges > {
925
+ const key = `${ options . lastCheckpoint } _${ options . nextCheckpoint } ` ;
926
+ const result = await this . checkpointChangesCache . fetch ( key , { context : { options } } ) ;
927
+ return result ! ;
928
+ }
929
+
930
+ private async getCheckpointChangesInternal ( options : GetCheckpointChangesOptions ) : Promise < CheckpointChanges > {
931
+ const dataUpdates = await this . getDataBucketChanges ( options ) ;
932
+ const parameterUpdates = await this . getParameterBucketChanges ( options ) ;
933
+
934
+ return {
935
+ ...dataUpdates ,
936
+ ...parameterUpdates
937
+ } ;
938
+ }
899
939
}
0 commit comments