Skip to content
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

SessionToken persistence implementation #13684

Merged
merged 13 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
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
1 change: 1 addition & 0 deletions Firestore/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Unreleased
- [changed] Improve efficiency of memory persistence when processing a large number of writes. (#13572)
- [changed] Prepare Firestore cache to support session token.
Copy link
Member

Choose a reason for hiding this comment

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

This change missed yesterday's code freeze. Please move to unreleased.


# 11.2.0
- [fixed] Marked all public classes with only readonly properties as `Sendable` to address
Expand Down
44 changes: 44 additions & 0 deletions Firestore/Example/Firestore.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

57 changes: 57 additions & 0 deletions Firestore/core/src/local/globals_cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @license
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef FIRESTORE_CORE_SRC_LOCAL_GLOBALS_CACHE_H_
#define FIRESTORE_CORE_SRC_LOCAL_GLOBALS_CACHE_H_

#include "Firestore/core/src/nanopb/byte_string.h"

namespace firebase {
namespace firestore {
namespace local {

using nanopb::ByteString;
tom-andersen marked this conversation as resolved.
Show resolved Hide resolved

/**
* General purpose cache for global values.
*
* Global state that cuts across components should be saved here. Following are
* contained herein:
*
* `sessionToken` tracks server interaction across Listen and Write streams.
* This facilitates cache synchronization and invalidation.
*/
class GlobalsCache {
public:
virtual ~GlobalsCache() = default;

/**
* Gets session token.
*/
virtual ByteString GetSessionToken() const = 0;

/**
* Sets session token.
*/
virtual void SetSessionToken(const ByteString& session_token) = 0;
};

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

#endif // FIRESTORE_CORE_SRC_LOCAL_GLOBALS_CACHE_H_
57 changes: 57 additions & 0 deletions Firestore/core/src/local/leveldb_globals_cache.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <string>

#include "Firestore/core/src/local/leveldb_globals_cache.h"
#include "Firestore/core/src/local/leveldb_key.h"
#include "Firestore/core/src/local/leveldb_persistence.h"

namespace firebase {
namespace firestore {
namespace local {

namespace {

const char* kSessionToken = "session_token";

}

LevelDbGlobalsCache::LevelDbGlobalsCache(LevelDbPersistence* db)
: db_(NOT_NULL(db)) {
}

ByteString LevelDbGlobalsCache::GetSessionToken() const {
auto key = LevelDbGlobalKey::Key(kSessionToken);

std::string encoded;
auto done = db_->current_transaction()->Get(key, &encoded);

if (!done.ok()) {
return ByteString();
}

return ByteString(encoded);
}

void LevelDbGlobalsCache::SetSessionToken(const ByteString& session_token) {
auto key = LevelDbGlobalKey::Key(kSessionToken);
db_->current_transaction()->Put(key, session_token.ToString());
}

} // namespace local
} // namespace firestore
} // namespace firebase
52 changes: 52 additions & 0 deletions Firestore/core/src/local/leveldb_globals_cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef FIRESTORE_CORE_SRC_LOCAL_LEVELDB_GLOBALS_CACHE_H_
#define FIRESTORE_CORE_SRC_LOCAL_LEVELDB_GLOBALS_CACHE_H_

#include "Firestore/core/src/local/globals_cache.h"

namespace firebase {
namespace firestore {
namespace local {

class LevelDbPersistence;

class LevelDbGlobalsCache : public GlobalsCache {
public:
/** Creates a new bundle cache in the given LevelDB. */
explicit LevelDbGlobalsCache(LevelDbPersistence* db);

/**
* Gets session token.
*/
ByteString GetSessionToken() const override;

/**
* Sets session token.
*/
void SetSessionToken(const ByteString& session_token) override;

private:
// The LevelDbGlobalsCache is owned by LevelDbPersistence.
LevelDbPersistence* db_ = nullptr;
};

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

#endif // FIRESTORE_CORE_SRC_LOCAL_LEVELDB_GLOBALS_CACHE_H_
36 changes: 36 additions & 0 deletions Firestore/core/src/local/leveldb_key.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ namespace local {
namespace {

const char* kVersionGlobalTable = "version";
const char* kGlobalsTable = "globals";
const char* kMutationsTable = "mutation";
const char* kDocumentMutationsTable = "document_mutation";
const char* kMutationQueuesTable = "mutation_queue";
Expand Down Expand Up @@ -159,6 +160,11 @@ enum ComponentLabel {
*/
DataMigrationName = 25,

/**
* The name of a global.
*/
GlobalName = 26,

/**
* A path segment describes just a single segment in a resource path. Path
* segments that occur sequentially in a key represent successive segments in
Expand Down Expand Up @@ -245,6 +251,10 @@ class Reader {
return ReadLabeledString(ComponentLabel::BundleId);
}

std::string ReadGlobalName() {
return ReadLabeledString(ComponentLabel::GlobalName);
}

std::string ReadQueryName() {
return ReadLabeledString(ComponentLabel::QueryName);
}
Expand Down Expand Up @@ -718,6 +728,10 @@ class Writer {
WriteLabeledString(ComponentLabel::TableName, table_name);
}

void WriteGlobalName(absl::string_view global_name) {
WriteLabeledString(ComponentLabel::GlobalName, global_name);
}

void WriteBatchId(model::BatchId batch_id) {
WriteLabeledInt32(ComponentLabel::BatchId, batch_id);
}
Expand Down Expand Up @@ -1206,6 +1220,28 @@ bool LevelDbRemoteDocumentReadTimeKey::Decode(absl::string_view key) {
return reader.ok();
}

std::string LevelDbGlobalKey::KeyPrefix() {
Writer writer;
writer.WriteTableName(kGlobalsTable);
return writer.result();
}

std::string LevelDbGlobalKey::Key(absl::string_view global_name) {
Writer writer;
writer.WriteTableName(kGlobalsTable);
writer.WriteGlobalName(global_name);
writer.WriteTerminator();
return writer.result();
}

bool LevelDbGlobalKey::Decode(absl::string_view key) {
Reader reader{key};
reader.ReadTableNameMatching(kGlobalsTable);
global_name_ = reader.ReadGlobalName();
reader.ReadTerminator();
return reader.ok();
}

std::string LevelDbBundleKey::KeyPrefix() {
Writer writer;
writer.WriteTableName(kBundlesTable);
Expand Down
35 changes: 35 additions & 0 deletions Firestore/core/src/local/leveldb_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,41 @@ class LevelDbNamedQueryKey {
std::string name_;
};

/**
* A key in the globals table, storing the bundle Id for each entry.
tom-andersen marked this conversation as resolved.
Show resolved Hide resolved
*/
class LevelDbGlobalKey {
public:
/**
* Creates a key prefix that points just before the first key of the table.
*/
static std::string KeyPrefix();

/**
* Creates a key that points to the key for the given global name.
*/
static std::string Key(absl::string_view global_name);

/**
* Decodes the given complete key, storing the decoded values in this
* instance.
*
* @return true if the key successfully decoded, false otherwise. If false is
* returned, this instance is in an undefined state until the next call to
* `Decode()`.
*/
ABSL_MUST_USE_RESULT
bool Decode(absl::string_view key);

/** The global name for this entry. */
tom-andersen marked this conversation as resolved.
Show resolved Hide resolved
const std::string& global_name() const {
return global_name_;
}

private:
std::string global_name_;
};

/**
* A key in the index_configuration table, storing the index definition proto,
* and the collection (group) it applies to.
Expand Down
5 changes: 5 additions & 0 deletions Firestore/core/src/local/leveldb_persistence.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ LevelDbPersistence::LevelDbPersistence(std::unique_ptr<leveldb::DB> db,
reference_delegate_ =
absl::make_unique<LevelDbLruReferenceDelegate>(this, lru_params);
bundle_cache_ = absl::make_unique<LevelDbBundleCache>(this, &serializer_);
globals_cache_ = absl::make_unique<LevelDbGlobalsCache>(this);

// TODO(gsoltis): set up a leveldb transaction for these operations.
target_cache_->Start();
Expand Down Expand Up @@ -250,6 +251,10 @@ LevelDbTargetCache* LevelDbPersistence::target_cache() {
return target_cache_.get();
}

LevelDbGlobalsCache* LevelDbPersistence::globals_cache() {
return globals_cache_.get();
}

LevelDbRemoteDocumentCache* LevelDbPersistence::remote_document_cache() {
return document_cache_.get();
}
Expand Down
4 changes: 4 additions & 0 deletions Firestore/core/src/local/leveldb_persistence.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "Firestore/core/src/credentials/user.h"
#include "Firestore/core/src/local/leveldb_bundle_cache.h"
#include "Firestore/core/src/local/leveldb_document_overlay_cache.h"
#include "Firestore/core/src/local/leveldb_globals_cache.h"
#include "Firestore/core/src/local/leveldb_index_manager.h"
#include "Firestore/core/src/local/leveldb_lru_reference_delegate.h"
#include "Firestore/core/src/local/leveldb_migrations.h"
Expand Down Expand Up @@ -84,6 +85,8 @@ class LevelDbPersistence : public Persistence {

LevelDbBundleCache* bundle_cache() override;

LevelDbGlobalsCache* globals_cache() override;

LevelDbDocumentOverlayCache* GetDocumentOverlayCache(
const credentials::User& user) override;
LevelDbOverlayMigrationManager* GetOverlayMigrationManager(
Expand Down Expand Up @@ -154,6 +157,7 @@ class LevelDbPersistence : public Persistence {
bool started_ = false;

std::unique_ptr<LevelDbBundleCache> bundle_cache_;
std::unique_ptr<LevelDbGlobalsCache> globals_cache_;
std::unordered_map<std::string, std::unique_ptr<LevelDbDocumentOverlayCache>>
document_overlay_caches_;
std::unordered_map<std::string,
Expand Down
33 changes: 33 additions & 0 deletions Firestore/core/src/local/memory_globals_cache.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "Firestore/core/src/local/memory_globals_cache.h"

namespace firebase {
namespace firestore {
namespace local {

ByteString MemoryGlobalsCache::GetSessionToken() const {
return session_token_;
}

void MemoryGlobalsCache::SetSessionToken(const ByteString& session_token) {
session_token_ = session_token;
}

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