Skip to content

Wire together LRU GC #1905

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 41 commits into from
Nov 26, 2018
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
ba07d15
Wire together LRU GC
Oct 3, 2018
46b6a95
Lint
Oct 3, 2018
ab90dd6
Fix declarations
Oct 3, 2018
b4ec0dc
Renaming, and using C++ namespaces
Oct 4, 2018
95e6f77
add NS tags to initializers, switch gc call to collect
Oct 5, 2018
42e1566
Remove timing from lru results struct
Oct 5, 2018
c2ace26
Switch to chrono for times
Oct 5, 2018
efac4fd
Move LruResults in C++ namespaces
Oct 5, 2018
eaa682f
Rename localstore garbage collection method
Oct 5, 2018
ee2cd93
Style
Oct 5, 2018
6b707ba
exempt chrono from linting
Oct 5, 2018
f8c5df3
Merge in master
Oct 5, 2018
dc948b9
Style
Oct 5, 2018
9aec574
BOOL -> bool
Oct 5, 2018
be136d3
Define unlimited cache size for ObjC
Oct 5, 2018
618f329
Fix type
Oct 5, 2018
161df33
Drop unused fields
Oct 8, 2018
e5259ad
Technically calls to GC should be in a transaction, the tests passed …
Oct 8, 2018
e0cda8c
Add transaction in local store as well
Oct 8, 2018
8622c2b
Fix subtle unsigned bug in test
Oct 8, 2018
6d13c58
Switch to serializedSize method
Oct 8, 2018
55a7608
Fix in-memory lru orphan calculation
Oct 8, 2018
c3098d6
Style
Oct 10, 2018
9894353
Wire up LRU GC (#1925)
Oct 11, 2018
bdee384
Merge branch 'master' into lru_with_master
Oct 15, 2018
17fc9e2
Add second timer setup, use NSInterval, drop post-compaction
Oct 16, 2018
2cc5374
Merge branch 'master' into lru_gc_disabled
Oct 16, 2018
ba76b15
Merge branch 'gsoltis/lru_gc_disabled' of https://github.com/firebase…
Oct 16, 2018
70f945b
Merge in upstream
Oct 16, 2018
47cc5b4
Update comment re orphaned documents
Oct 16, 2018
f20c50a
Style
Oct 16, 2018
3a1bc20
Remove unnecessary to_string calls
Oct 17, 2018
ba406b6
LRU tweaks (#1961)
Oct 17, 2018
515b0c3
Merging in master
Nov 26, 2018
0bdfb98
Style
Nov 26, 2018
6297c33
Merge branch 'master' into lru_with_master
Nov 26, 2018
3107b3a
pod update
Nov 26, 2018
d355437
Fix lint tag
Nov 26, 2018
7a70f23
Merge in upstream
Nov 26, 2018
40c34aa
Fix merge conflict
Nov 26, 2018
e485277
Use DelayedOperation directly, since it can be internally empty
Nov 26, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Firestore/Example/Tests/Local/FSTLRUGarbageCollectorTests.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@

#import <XCTest/XCTest.h>

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

@protocol FSTPersistence;
struct FSTLruGcParams;

NS_ASSUME_NONNULL_BEGIN

@interface FSTLRUGarbageCollectorTests : XCTestCase

- (id<FSTPersistence>)newPersistenceWithLruGcParams:(FSTLruGcParams)lruGcParams;
- (id<FSTPersistence>)newPersistenceWithLruParams:(firebase::firestore::local::LruParams)lruParams;

@end

Expand Down
30 changes: 16 additions & 14 deletions Firestore/Example/Tests/Local/FSTLRUGarbageCollectorTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@

namespace testutil = firebase::firestore::testutil;
using firebase::firestore::auth::User;
using firebase::firestore::local::LruParams;
using firebase::firestore::local::LruResults;
using firebase::firestore::model::DocumentKey;
using firebase::firestore::model::DocumentKeyHash;
using firebase::firestore::model::DocumentKeySet;
Expand Down Expand Up @@ -82,9 +84,9 @@ - (FSTLRUGarbageCollector *)garbageCollectorFromPersistence:(id<FSTPersistence>)
return ((id<FSTLRUDelegate>)persistence.referenceDelegate).gc;
}

- (void)newTestResourcesWithLruGcParams:(FSTLruGcParams)lruGcParams {
- (void)newTestResourcesWithLruParams:(LruParams)lruParams {
HARD_ASSERT(_persistence == nil, "Persistence already created");
_persistence = [self newPersistenceWithLruGcParams:lruGcParams];
_persistence = [self newPersistenceWithLruParams:lruParams];
_queryCache = [_persistence queryCache];
_documentCache = [_persistence remoteDocumentCache];
_mutationQueue = [_persistence mutationQueueForUser:_user];
Expand All @@ -96,10 +98,10 @@ - (void)newTestResourcesWithLruGcParams:(FSTLruGcParams)lruGcParams {
}

- (void)newTestResources {
[self newTestResourcesWithLruGcParams:FSTLruGcParams::Default()];
[self newTestResourcesWithLruParams:LruParams::Default()];
}

- (id<FSTPersistence>)newPersistenceWithLruGcParams:(FSTLruGcParams)lruGcParams {
- (id<FSTPersistence>)newPersistenceWithLruParams:(LruParams)lruParams {
@throw FSTAbstractMethodException(); // NOLINT
}

Expand Down Expand Up @@ -673,8 +675,8 @@ - (void)testGetsSize {
- (void)testDisabled {
if ([self isTestBaseClass]) return;

FSTLruGcParams params = FSTLruGcParams::Disabled();
[self newTestResourcesWithLruGcParams:params];
LruParams params = LruParams::Disabled();
[self newTestResourcesWithLruParams:params];

_persistence.run("fill cache", [&]() {
// Simulate a bunch of ack'd mutations
Expand All @@ -684,7 +686,7 @@ - (void)testDisabled {
}
});

FSTLruGcResults results = [_gc tryRunGcWithLiveTargets:@{}];
LruResults results = [_gc collectWithLiveTargets:@{}];
XCTAssertFalse(results.didRun);

[_persistence shutdown];
Expand All @@ -693,8 +695,8 @@ - (void)testDisabled {
- (void)testCacheTooSmall {
if ([self isTestBaseClass]) return;

FSTLruGcParams params = FSTLruGcParams::Disabled();
[self newTestResourcesWithLruGcParams:params];
LruParams params = LruParams::Disabled();
[self newTestResourcesWithLruParams:params];

_persistence.run("fill cache", [&]() {
// Simulate a bunch of ack'd mutations
Expand All @@ -709,7 +711,7 @@ - (void)testCacheTooSmall {
XCTAssertLessThan(cacheSize, params.minBytesThreshold);

// Try collection and verify that it didn't run
FSTLruGcResults results = [_gc tryRunGcWithLiveTargets:@{}];
LruResults results = [_gc collectWithLiveTargets:@{}];
XCTAssertFalse(results.didRun);

[_persistence shutdown];
Expand All @@ -718,10 +720,10 @@ - (void)testCacheTooSmall {
- (void)testGCRan {
if ([self isTestBaseClass]) return;

FSTLruGcParams params = FSTLruGcParams::Default();
LruParams params = LruParams::Default();
// Set a low threshold so we will definitely run
params.minBytesThreshold = 100;
[self newTestResourcesWithLruGcParams:params];
[self newTestResourcesWithLruParams:params];

// Add 100 targets and 10 documents to each
for (int i = 0; i < 100; i++) {
Expand All @@ -737,8 +739,8 @@ - (void)testGCRan {
}

// Mark nothing as live, so everything is eligible.
FSTLruGcResults results = _persistence.run(
"GC", [&]() -> FSTLruGcResults { return [_gc tryRunGcWithLiveTargets:@{}]; });
LruResults results =
_persistence.run("GC", [&]() -> LruResults { return [_gc collectWithLiveTargets:@{}]; });

// By default, we collect 10% of the sequence numbers. Since we added 100 targets,
// that should be 10 targets with 10 documents each, for a total of 100 documents.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@

#import "Firestore/Example/Tests/Local/FSTLRUGarbageCollectorTests.h"
#import "Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h"
#import "Firestore/Source/Local/FSTLRUGarbageCollector.h"
#import "Firestore/Source/Local/FSTLevelDB.h"

using firebase::firestore::local::LruParams;

NS_ASSUME_NONNULL_BEGIN

@interface FSTLevelDBLRUGarbageCollectorTests : FSTLRUGarbageCollectorTests
@end

@implementation FSTLevelDBLRUGarbageCollectorTests

- (id<FSTPersistence>)newPersistenceWithLruGcParams:(FSTLruGcParams)lruGcParams {
return [FSTPersistenceTestHelpers levelDBPersistenceWithLruGcParams:lruGcParams];
- (id<FSTPersistence>)newPersistenceWithLruParams:(LruParams)lruParams {
return [FSTPersistenceTestHelpers levelDBPersistenceWithLruParams:lruParams];
}

@end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,20 @@
#import "Firestore/Example/Tests/Local/FSTLRUGarbageCollectorTests.h"

#import "Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h"
#import "Firestore/Source/Local/FSTLRUGarbageCollector.h"
#import "Firestore/Source/Local/FSTMemoryPersistence.h"

using firebase::firestore::local::LruParams;

NS_ASSUME_NONNULL_BEGIN

@interface FSTMemoryLRUGarbageCollectionTests : FSTLRUGarbageCollectorTests
@end

@implementation FSTMemoryLRUGarbageCollectionTests

- (id<FSTPersistence>)newPersistenceWithLruGcParams:(FSTLruGcParams)lruGcParams {
return [FSTPersistenceTestHelpers lruMemoryPersistenceWithLruGcParams:lruGcParams];
- (id<FSTPersistence>)newPersistenceWithLruParams:(LruParams)lruParams {
return [FSTPersistenceTestHelpers lruMemoryPersistenceWithLruParams:lruParams];
}

@end
Expand Down
7 changes: 4 additions & 3 deletions Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@

#import <Foundation/Foundation.h>

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

@class FSTLevelDB;
@class FSTMemoryPersistence;
struct FSTLruGcParams;

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -55,14 +55,15 @@ NS_ASSUME_NONNULL_BEGIN
*
* Sets up the LRU garbage collection to use the provided params.
*/
+ (FSTLevelDB *)levelDBPersistenceWithLruGcParams:(FSTLruGcParams)lruGcParams;
+ (FSTLevelDB *)levelDBPersistenceWithLruParams:(firebase::firestore::local::LruParams)lruParams;

/** Creates and starts a new FSTMemoryPersistence instance for testing. */
+ (FSTMemoryPersistence *)eagerGCMemoryPersistence;

+ (FSTMemoryPersistence *)lruMemoryPersistence;

+ (FSTMemoryPersistence *)lruMemoryPersistenceWithLruGcParams:(FSTLruGcParams)lruGcParams;
+ (FSTMemoryPersistence *)lruMemoryPersistenceWithLruParams:
(firebase::firestore::local::LruParams)lruParams;
@end

NS_ASSUME_NONNULL_END
21 changes: 11 additions & 10 deletions Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <utility>

#import "Firestore/Source/Local/FSTLRUGarbageCollector.h"
#import "Firestore/Source/Local/FSTLevelDB.h"
#import "Firestore/Source/Local/FSTLocalSerializer.h"
#import "Firestore/Source/Local/FSTMemoryPersistence.h"
Expand All @@ -30,6 +31,7 @@
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"

namespace util = firebase::firestore::util;
using firebase::firestore::local::LruParams;
using firebase::firestore::model::DatabaseId;
using firebase::firestore::util::Path;
using firebase::firestore::util::Status;
Expand Down Expand Up @@ -61,14 +63,13 @@ + (Path)levelDBDir {
}

+ (FSTLevelDB *)levelDBPersistenceWithDir:(Path)dir {
return [self levelDBPersistenceWithDir:dir lruGcParams:FSTLruGcParams::Default()];
return [self levelDBPersistenceWithDir:dir lruParams:LruParams::Default()];
}

+ (FSTLevelDB *)levelDBPersistenceWithDir:(Path)dir lruGcParams:(FSTLruGcParams)params {
+ (FSTLevelDB *)levelDBPersistenceWithDir:(Path)dir lruParams:(LruParams)params {
FSTLocalSerializer *serializer = [self localSerializer];
FSTLevelDB *db = [[FSTLevelDB alloc] initWithDirectory:std::move(dir)
serializer:serializer
lruGcParams:params];
FSTLevelDB *db =
[[FSTLevelDB alloc] initWithDirectory:std::move(dir) serializer:serializer lruParams:params];
Status status = [db start];
if (!status.ok()) {
[NSException raise:NSInternalInconsistencyException
Expand All @@ -78,8 +79,8 @@ + (FSTLevelDB *)levelDBPersistenceWithDir:(Path)dir lruGcParams:(FSTLruGcParams)
return db;
}

+ (FSTLevelDB *)levelDBPersistenceWithLruGcParams:(FSTLruGcParams)lruGcParams {
return [self levelDBPersistenceWithDir:[self levelDBDir] lruGcParams:lruGcParams];
+ (FSTLevelDB *)levelDBPersistenceWithLruParams:(LruParams)lruParams {
return [self levelDBPersistenceWithDir:[self levelDBDir] lruParams:lruParams];
}

+ (FSTLevelDB *)levelDBPersistence {
Expand All @@ -98,13 +99,13 @@ + (FSTMemoryPersistence *)eagerGCMemoryPersistence {
}

+ (FSTMemoryPersistence *)lruMemoryPersistence {
return [self lruMemoryPersistenceWithLruGcParams:FSTLruGcParams::Default()];
return [self lruMemoryPersistenceWithLruParams:LruParams::Default()];
}

+ (FSTMemoryPersistence *)lruMemoryPersistenceWithLruGcParams:(FSTLruGcParams)lruGcParams {
+ (FSTMemoryPersistence *)lruMemoryPersistenceWithLruParams:(LruParams)lruParams {
FSTLocalSerializer *serializer = [self localSerializer];
FSTMemoryPersistence *persistence =
[FSTMemoryPersistence persistenceWithLruGcParams:lruGcParams serializer:serializer];
[FSTMemoryPersistence persistenceWithLruParams:lruParams serializer:serializer];
Status status = [persistence start];
if (!status.ok()) {
[NSException raise:NSInternalInconsistencyException
Expand Down
21 changes: 10 additions & 11 deletions Firestore/Source/Core/FSTFirestoreClient.mm
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
using firebase::firestore::auth::CredentialsProvider;
using firebase::firestore::auth::User;
using firebase::firestore::core::DatabaseInfo;
using firebase::firestore::local::LruParams;
using firebase::firestore::model::DatabaseId;
using firebase::firestore::model::DocumentKeySet;
using firebase::firestore::model::OnlineState;
Expand Down Expand Up @@ -191,7 +192,7 @@ - (void)initializeWithUser:(const User &)user usePersistence:(BOOL)usePersistenc
// TODO(gsoltis): enable LRU GC once API is finalized
FSTLevelDB *ldb = [[FSTLevelDB alloc] initWithDirectory:std::move(dir)
serializer:serializer
lruGcParams:FSTLruGcParams::Disabled()];
lruParams:LruParams::Disabled()];
_lruDelegate = ldb.referenceDelegate;
_persistence = ldb;
[self scheduleLruGarbageCollection];
Expand Down Expand Up @@ -242,16 +243,14 @@ - (void)initializeWithUser:(const User &)user usePersistence:(BOOL)usePersistenc
*/
- (void)scheduleLruGarbageCollection {
long delay = _gcHasRun ? _initialGcDelay : _regularGcDelay;
_lruCallback = [_workerDispatchQueue
dispatchAfterDelay:delay
timerID:FSTLruGCTimer
block:^{
FSTLruGcResults results =
[self->_localStore tryLruGarbageCollection:self->_lruDelegate.gc];
self->_gcHasRun = YES;
LOG_DEBUG(results.ToString().c_str());
[self scheduleLruGarbageCollection];
}];
_lruCallback =
[_workerDispatchQueue dispatchAfterDelay:delay
timerID:FSTTimerIDGarbageCollectionDelay
block:^{
[self->_localStore collectGarbage:self->_lruDelegate.gc];
self->_gcHasRun = YES;
[self scheduleLruGarbageCollection];
}];
}

- (void)credentialDidChangeWithUser:(const User &)user {
Expand Down
65 changes: 31 additions & 34 deletions Firestore/Source/Local/FSTLRUGarbageCollector.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,39 @@

extern const firebase::firestore::model::ListenSequenceNumber kFSTListenSequenceNumberInvalid;

struct FSTLruGcParams {
static FSTLruGcParams Default() {
return FSTLruGcParams{.minBytesThreshold = 100 * 1024 * 1024,
.percentileToCollect = 10,
.maximumSequenceNumbersToCollect = 1000};
namespace firebase {
namespace firestore {
namespace local {

struct LruParams {
static LruParams Default() {
return LruParams{100 * 1024 * 1024, 10, 1000};
}

static FSTLruGcParams Disabled() {
return FSTLruGcParams{.minBytesThreshold = kFIRFirestorePersistenceCacheSizeUnlimited};
static LruParams Disabled() {
return LruParams{kFIRFirestorePersistenceCacheSizeUnlimited, 0, 0};
}

long minBytesThreshold;
int percentileToCollect;
int maximumSequenceNumbersToCollect;
};

struct LruResults {
static LruResults DidNotRun() {
return LruResults{NO, 0, 0, 0};
}

BOOL didRun;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C++ has a boolean type bool whose literals are true and false. (BOOL, YES, NO are Objective-C).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, done.

int sequenceNumbersCollected;
int targetsRemoved;
int documentsRemoved;
};

} // namespace local
} // namespace firestore
} // namespace firebase

/**
* Persistence layers intending to use LRU Garbage collection should implement this protocol. This
* protocol defines the operations that the LRU garbage collector needs from the persistence layer.
Expand Down Expand Up @@ -96,38 +113,17 @@ struct FSTLruGcParams {

@end

struct FSTLruGcResults {
static FSTLruGcResults DidNotRun() {
return FSTLruGcResults{.didRun = NO};
}

std::string ToString() const;

long total_duration() const {
return targetCountDurationMs + upperBoundDurationMs + removedTargetsDurationMs +
removedDocumentsDurationMs + dbCompactionDurationMs;
}

BOOL didRun;

long targetCountDurationMs;
long upperBoundDurationMs;
long removedTargetsDurationMs;
long removedDocumentsDurationMs;
long dbCompactionDurationMs;

int sequenceNumbersCollected;
int targetsRemoved;
int documentsRemoved;
};

/**
* FSTLRUGarbageCollector defines the LRU algorithm used to clean up old documents and targets. It
* is persistence-agnostic, as long as proper delegate is provided.
*/
@interface FSTLRUGarbageCollector : NSObject

- (instancetype)initWithDelegate:(id<FSTLRUDelegate>)delegate params:(FSTLruGcParams)params;
- (instancetype)initWithDelegate:(id<FSTLRUDelegate>)delegate
params:(firebase::firestore::local::LruParams)params
NS_DESIGNATED_INITIALIZER;

- (instancetype)init NS_UNAVAILABLE;

/**
* Given a target percentile, return the number of queries that make up that percentage of the
Expand Down Expand Up @@ -159,6 +155,7 @@ struct FSTLruGcResults {

- (size_t)byteSize;

- (FSTLruGcResults)tryRunGcWithLiveTargets:(NSDictionary<NSNumber *, FSTQueryData *> *)liveTargets;
- (firebase::firestore::local::LruResults)collectWithLiveTargets:
(NSDictionary<NSNumber *, FSTQueryData *> *)liveTargets;

@end
Loading