-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Keep track of number of queries in the query cache #776
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
Changes from all commits
60d36af
52ad8cc
93a84b1
0580b9a
77e4ed2
d3f269c
a6fa651
578a020
d7290cc
9dfd89d
ba24516
638a9d5
09ac0d3
2019e8d
55ec377
8ecba99
f2308ef
87767f6
187fc36
1636f59
3ab71f4
8ecf533
9840e4a
43a98e3
c910583
aefb3cc
32a33d2
29db2e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,21 +16,22 @@ | |
|
||
#include "Firestore/Source/Local/FSTLevelDBMigrations.h" | ||
|
||
#include <leveldb/db.h> | ||
#include <leveldb/write_batch.h> | ||
#include "leveldb/write_batch.h" | ||
|
||
#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h" | ||
#import "Firestore/Source/Local/FSTLevelDB.h" | ||
#import "Firestore/Source/Local/FSTLevelDBKey.h" | ||
#import "Firestore/Source/Local/FSTLevelDBQueryCache.h" | ||
#import "Firestore/Source/Local/FSTWriteGroup.h" | ||
#import "Firestore/Source/Util/FSTAssert.h" | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
// Current version of the schema defined in this file. | ||
static FSTLevelDBSchemaVersion kSchemaVersion = 1; | ||
static FSTLevelDBSchemaVersion kSchemaVersion = 2; | ||
|
||
using leveldb::DB; | ||
using leveldb::Iterator; | ||
using leveldb::Status; | ||
using leveldb::Slice; | ||
using leveldb::WriteOptions; | ||
|
@@ -57,6 +58,31 @@ static void SaveVersion(FSTLevelDBSchemaVersion version, FSTWriteGroup *group) { | |
[group setData:version_string forKey:key]; | ||
} | ||
|
||
/** | ||
* This function counts the number of targets that currently exist in the given db. It | ||
* then reads the target global row, adds the count to the metadata from that row, and writes | ||
* the metadata back. | ||
* | ||
* It assumes the metadata has already been written and is able to be read in this transaction. | ||
*/ | ||
static void AddTargetCount(std::shared_ptr<DB> db, FSTWriteGroup *group) { | ||
std::unique_ptr<Iterator> it(db->NewIterator([FSTLevelDB standardReadOptions])); | ||
Slice start_key = [FSTLevelDBTargetKey keyPrefix]; | ||
it->Seek(start_key); | ||
|
||
int32_t count = 0; | ||
while (it->Valid() && it->key().starts_with(start_key)) { | ||
count++; | ||
it->Next(); | ||
} | ||
|
||
FSTPBTargetGlobal *targetGlobal = [FSTLevelDBQueryCache readTargetMetadataFromDB:db]; | ||
FSTCAssert(targetGlobal != nil, | ||
@"We should have a metadata row as it was added in an earlier migration"); | ||
targetGlobal.targetCount = count; | ||
[group setMessage:targetGlobal forKey:[FSTLevelDBTargetGlobalKey key]]; | ||
} | ||
|
||
@implementation FSTLevelDBMigrations | ||
|
||
+ (FSTLevelDBSchemaVersion)schemaVersionForDB:(std::shared_ptr<DB>)db { | ||
|
@@ -80,6 +106,16 @@ + (void)runMigrationsOnDB:(std::shared_ptr<DB>)db { | |
case 0: | ||
EnsureTargetGlobal(db, group); | ||
// Fallthrough | ||
case 1: | ||
// We need to make sure we have metadata, since we're going to read and modify it | ||
// in this migration. Commit the current transaction and start a new one. Since we're | ||
// committing, we need to save a version. It's safe to save this one, if we crash | ||
// after saving we'll resume from this step when we try to migrate. | ||
SaveVersion(1, group); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is pretty gross and is another poke at the idea that we should make WriteGroups into Transactions that support reading back pending values. (This is not actionable feedback here; more of a reminder for myself.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noted. Not sure it's really worth doing yet, but I can see how the current state is less than optimal. |
||
[group writeToDB:db]; | ||
group = [FSTWriteGroup groupWithAction:@"Migrations"]; | ||
AddTargetCount(db, group); | ||
// Fallthrough | ||
default: | ||
if (currentVersion < kSchemaVersion) { | ||
SaveVersion(kSchemaVersion, group); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no separate storage for different logical tables in LevelDB so it's important to test that your key ranges are properly bounded. Please make sure to insert adversarial key prefixes to verify that your key prefix is properly constructed.
See here for an example:
firebase-ios-sdk/Firestore/Example/Tests/Local/FSTLevelDBMutationQueueTests.mm
Line 107 in 8003348
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add a key to test this, but it appears that the way we construct keys includes a table name and terminator in the prefix. I'm fairly certain that means as a general rule we're ok using a full tablename as a prefix for iteration bounds. There actually already exists an adversarial key, the target_global table/key (vs a table name of 'target'), but it is not explicit in the test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right: I added the explicit terminators so that we couldn't be tricked by "food" when searching in the table "foo". However, having been bitten by this by failing to use the routines correctly I'm paranoid.