Skip to content

Commit aa326a4

Browse files
authored
Migrate FSTLRUGarbageCollector to C++ LruGarbageCollector (#3685)
* Add ReferenceDelegate * Remove Objective-C crutches from model/types.h and query_cache.h * Add C++ LruGarbageCollector * Add delegate bridges for LruDelegate and ReferenceDelegate * Migrate from FSTLRUGarbageCollector to C++ LruGarbageCollector
1 parent 5cdff78 commit aa326a4

22 files changed

+683
-343
lines changed

Firestore/Example/Tests/Local/FSTLRUGarbageCollectorTests.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@
1818

1919
#import "Firestore/Source/Local/FSTLRUGarbageCollector.h"
2020

21+
namespace firebase {
22+
namespace firestore {
23+
namespace local {
24+
25+
class LruParams;
26+
27+
} // namespace local
28+
} // namespace firestore
29+
} // namespace firebase
30+
2131
@protocol FSTPersistence;
2232

2333
NS_ASSUME_NONNULL_BEGIN

Firestore/Example/Tests/Local/FSTLRUGarbageCollectorTests.mm

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424
#include <vector>
2525

2626
#import "Firestore/Example/Tests/Util/FSTHelpers.h"
27-
#import "Firestore/Source/Local/FSTLRUGarbageCollector.h"
2827
#import "Firestore/Source/Local/FSTPersistence.h"
2928
#import "Firestore/Source/Util/FSTClasses.h"
3029

3130
#include "Firestore/core/include/firebase/firestore/timestamp.h"
3231
#include "Firestore/core/src/firebase/firestore/auth/user.h"
3332
#include "Firestore/core/src/firebase/firestore/core/query.h"
33+
#include "Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h"
3434
#include "Firestore/core/src/firebase/firestore/local/mutation_queue.h"
3535
#include "Firestore/core/src/firebase/firestore/local/query_cache.h"
3636
#include "Firestore/core/src/firebase/firestore/local/query_data.h"
@@ -48,6 +48,7 @@
4848
namespace testutil = firebase::firestore::testutil;
4949
using firebase::Timestamp;
5050
using firebase::firestore::auth::User;
51+
using firebase::firestore::local::LruGarbageCollector;
5152
using firebase::firestore::local::LruParams;
5253
using firebase::firestore::local::LruResults;
5354
using firebase::firestore::local::MutationQueue;
@@ -84,7 +85,7 @@ @implementation FSTLRUGarbageCollectorTests {
8485
RemoteDocumentCache *_documentCache;
8586
MutationQueue *_mutationQueue;
8687
id<FSTLRUDelegate> _lruDelegate;
87-
FSTLRUGarbageCollector *_gc;
88+
LruGarbageCollector *_gc;
8889
ListenSequenceNumber _initialSequenceNumber;
8990
User _user;
9091
ReferenceSet _additionalReferences;
@@ -140,28 +141,26 @@ - (void)expectSentinelRemoved:(const DocumentKey &)key {
140141

141142
- (ListenSequenceNumber)sequenceNumberForQueryCount:(int)queryCount {
142143
return _persistence.run(
143-
"gc", [&]() -> ListenSequenceNumber { return [_gc sequenceNumberForQueryCount:queryCount]; });
144+
"gc", [&]() -> ListenSequenceNumber { return _gc->SequenceNumberForQueryCount(queryCount); });
144145
}
145146

146147
- (int)queryCountForPercentile:(int)percentile {
147148
return _persistence.run("query count",
148-
[&]() -> int { return [_gc queryCountForPercentile:percentile]; });
149+
[&]() -> int { return _gc->QueryCountForPercentile(percentile); });
149150
}
150151

151152
- (int)removeQueriesThroughSequenceNumber:(ListenSequenceNumber)sequenceNumber
152153
liveQueries:
153154
(const std::unordered_map<TargetId, QueryData> &)liveQueries {
154-
return _persistence.run("gc", [&]() -> int {
155-
return [_gc removeQueriesUpThroughSequenceNumber:sequenceNumber liveQueries:liveQueries];
156-
});
155+
return _persistence.run("gc",
156+
[&]() -> int { return _gc->RemoveTargets(sequenceNumber, liveQueries); });
157157
}
158158

159159
// Removes documents that are not part of a target or a mutation and have a sequence number
160160
// less than or equal to the given sequence number.
161161
- (int)removeOrphanedDocumentsThroughSequenceNumber:(ListenSequenceNumber)sequenceNumber {
162-
return _persistence.run("gc", [&]() -> int {
163-
return [_gc removeOrphanedDocumentsThroughSequenceNumber:sequenceNumber];
164-
});
162+
return _persistence.run("gc",
163+
[&]() -> int { return _gc->RemoveOrphanedDocuments(sequenceNumber); });
165164
}
166165

167166
- (QueryData)nextTestQuery {
@@ -284,7 +283,7 @@ - (void)testSequenceNumberNoQueries {
284283

285284
// No queries... should get invalid sequence number (-1)
286285
[self newTestResources];
287-
XCTAssertEqual(kFSTListenSequenceNumberInvalid, [self sequenceNumberForQueryCount:0]);
286+
XCTAssertEqual(local::kListenSequenceNumberInvalid, [self sequenceNumberForQueryCount:0]);
288287
[_persistence shutdown];
289288
}
290289

@@ -672,7 +671,7 @@ - (void)testGetsSize {
672671

673672
[self newTestResources];
674673

675-
size_t initialSize = [_gc byteSize];
674+
size_t initialSize = _gc->CalculateByteSize();
676675

677676
_persistence.run("fill cache", [&]() {
678677
// Simulate a bunch of ack'd mutations
@@ -682,7 +681,7 @@ - (void)testGetsSize {
682681
}
683682
});
684683

685-
size_t finalSize = [_gc byteSize];
684+
size_t finalSize = _gc->CalculateByteSize();
686685
XCTAssertGreaterThan(finalSize, initialSize);
687686

688687
[_persistence shutdown];
@@ -702,9 +701,8 @@ - (void)testDisabled {
702701
}
703702
});
704703

705-
LruResults results =
706-
_persistence.run("GC", [&]() -> LruResults { return [_gc collectWithLiveTargets:{}]; });
707-
XCTAssertFalse(results.didRun);
704+
LruResults results = _persistence.run("GC", [&]() -> LruResults { return _gc->Collect({}); });
705+
XCTAssertFalse(results.did_run);
708706

709707
[_persistence shutdown];
710708
}
@@ -723,14 +721,13 @@ - (void)testCacheTooSmall {
723721
}
724722
});
725723

726-
int cacheSize = (int)[_gc byteSize];
724+
int cacheSize = (int)_gc->CalculateByteSize();
727725
// Verify that we don't have enough in our cache to warrant collection
728-
XCTAssertLessThan(cacheSize, params.minBytesThreshold);
726+
XCTAssertLessThan(cacheSize, params.min_bytes_threshold);
729727

730728
// Try collection and verify that it didn't run
731-
LruResults results =
732-
_persistence.run("GC", [&]() -> LruResults { return [_gc collectWithLiveTargets:{}]; });
733-
XCTAssertFalse(results.didRun);
729+
LruResults results = _persistence.run("GC", [&]() -> LruResults { return _gc->Collect({}); });
730+
XCTAssertFalse(results.did_run);
734731

735732
[_persistence shutdown];
736733
}
@@ -740,7 +737,7 @@ - (void)testGCRan {
740737

741738
LruParams params = LruParams::Default();
742739
// Set a low threshold so we will definitely run
743-
params.minBytesThreshold = 100;
740+
params.min_bytes_threshold = 100;
744741
[self newTestResourcesWithLruParams:params];
745742

746743
// Add 100 targets and 10 documents to each
@@ -757,14 +754,13 @@ - (void)testGCRan {
757754
}
758755

759756
// Mark nothing as live, so everything is eligible.
760-
LruResults results =
761-
_persistence.run("GC", [&]() -> LruResults { return [_gc collectWithLiveTargets:{}]; });
757+
LruResults results = _persistence.run("GC", [&]() -> LruResults { return _gc->Collect({}); });
762758

763759
// By default, we collect 10% of the sequence numbers. Since we added 100 targets,
764760
// that should be 10 targets with 10 documents each, for a total of 100 documents.
765-
XCTAssertTrue(results.didRun);
766-
XCTAssertEqual(10, results.targetsRemoved);
767-
XCTAssertEqual(100, results.documentsRemoved);
761+
XCTAssertTrue(results.did_run);
762+
XCTAssertEqual(10, results.targets_removed);
763+
XCTAssertEqual(100, results.documents_removed);
768764
[_persistence shutdown];
769765
}
770766

Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,21 @@
1616

1717
#import <Foundation/Foundation.h>
1818

19-
#import "Firestore/Source/Local/FSTLRUGarbageCollector.h"
2019
#include "Firestore/core/src/firebase/firestore/util/path.h"
2120

2221
@class FSTLevelDB;
2322
@class FSTMemoryPersistence;
2423

24+
namespace firebase {
25+
namespace firestore {
26+
namespace local {
27+
28+
class LruParams;
29+
30+
} // namespace local
31+
} // namespace firestore
32+
} // namespace firebase
33+
2534
NS_ASSUME_NONNULL_BEGIN
2635

2736
@interface FSTPersistenceTestHelpers : NSObject

Firestore/Example/Tests/Util/FSTHelpers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ class TestTargetMetadataProvider : public TargetMetadataProvider {
182182
const std::vector<model::TargetId> &limbo_targets);
183183

184184
/**
185-
* Creates an `TestTargetMetadataProvider` that behaves as if there's an established listen for
185+
* Creates a `TestTargetMetadataProvider` that behaves as if there's an established listen for
186186
* each of the given targets, where each target has not seen any previous document.
187187
*
188188
* Internally this means that the `GetRemoteKeysForTarget` callback for these targets will return

Firestore/Source/Local/FSTLRUGarbageCollector.h

Lines changed: 3 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -25,53 +25,18 @@
2525
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
2626
#include "Firestore/core/src/firebase/firestore/model/types.h"
2727

28-
@class FSTLRUGarbageCollector;
29-
30-
namespace local = firebase::firestore::local;
31-
namespace model = firebase::firestore::model;
32-
33-
extern const model::ListenSequenceNumber kFSTListenSequenceNumberInvalid;
34-
3528
namespace firebase {
3629
namespace firestore {
3730
namespace local {
3831

39-
struct LruParams {
40-
static LruParams Default() {
41-
return LruParams{100 * 1024 * 1024, 10, 1000};
42-
}
43-
44-
static LruParams Disabled() {
45-
return LruParams{api::Settings::CacheSizeUnlimited, 0, 0};
46-
}
47-
48-
static LruParams WithCacheSize(int64_t cacheSize) {
49-
LruParams params = Default();
50-
params.minBytesThreshold = cacheSize;
51-
return params;
52-
}
53-
54-
int64_t minBytesThreshold;
55-
int percentileToCollect;
56-
int maximumSequenceNumbersToCollect;
57-
};
58-
59-
struct LruResults {
60-
static LruResults DidNotRun() {
61-
return LruResults{/* didRun= */ false, 0, 0, 0};
62-
}
63-
64-
bool didRun;
65-
int sequenceNumbersCollected;
66-
int targetsRemoved;
67-
int documentsRemoved;
68-
};
32+
class LruGarbageCollector;
6933

7034
} // namespace local
7135
} // namespace firestore
7236
} // namespace firebase
7337

7438
namespace local = firebase::firestore::local;
39+
namespace model = firebase::firestore::model;
7540

7641
/**
7742
* Persistence layers intending to use LRU Garbage collection should implement this protocol. This
@@ -111,51 +76,6 @@ namespace local = firebase::firestore::local;
11176
- (size_t)sequenceNumberCount;
11277

11378
/** Access to the underlying LRU Garbage collector instance. */
114-
@property(strong, nonatomic, readonly) FSTLRUGarbageCollector *gc;
115-
116-
@end
117-
118-
/**
119-
* FSTLRUGarbageCollector defines the LRU algorithm used to clean up old documents and targets. It
120-
* is persistence-agnostic, as long as proper delegate is provided.
121-
*/
122-
@interface FSTLRUGarbageCollector : NSObject
123-
124-
- (instancetype)initWithDelegate:(id<FSTLRUDelegate>)delegate
125-
params:(local::LruParams)params NS_DESIGNATED_INITIALIZER;
126-
127-
- (instancetype)init NS_UNAVAILABLE;
128-
129-
/**
130-
* Given a target percentile, return the number of queries that make up that percentage of the
131-
* queries that are cached. For instance, if 20 queries are cached, and the percentile is 40, the
132-
* result will be 8.
133-
*/
134-
- (int)queryCountForPercentile:(NSUInteger)percentile;
135-
136-
/**
137-
* Given a number of queries n, return the nth sequence number in the cache.
138-
*/
139-
- (model::ListenSequenceNumber)sequenceNumberForQueryCount:(NSUInteger)queryCount;
140-
141-
/**
142-
* Removes queries that are not currently live (as indicated by presence in the liveQueries map) and
143-
* have a sequence number less than or equal to the given sequence number.
144-
*/
145-
- (int)removeQueriesUpThroughSequenceNumber:(model::ListenSequenceNumber)sequenceNumber
146-
liveQueries:
147-
(const std::unordered_map<model::TargetId, local::QueryData> &)
148-
liveQueries;
149-
150-
/**
151-
* Removes all unreferenced documents from the cache that have a sequence number less than or equal
152-
* to the given sequence number. Returns the number of documents removed.
153-
*/
154-
- (int)removeOrphanedDocumentsThroughSequenceNumber:(model::ListenSequenceNumber)sequenceNumber;
155-
156-
- (size_t)byteSize;
157-
158-
- (local::LruResults)collectWithLiveTargets:
159-
(const std::unordered_map<model::TargetId, local::QueryData> &)liveTargets;
79+
- (local::LruGarbageCollector *)gc;
16080

16181
@end

0 commit comments

Comments
 (0)