Skip to content

Commit

Permalink
SessionToken persistence implementation (#13684)
Browse files Browse the repository at this point in the history
Co-authored-by: Wu-Hui <[email protected]>
  • Loading branch information
tom-andersen and wu-hui authored Sep 25, 2024
1 parent 96ca3cd commit 2893101
Show file tree
Hide file tree
Showing 18 changed files with 594 additions and 0 deletions.
1 change: 1 addition & 0 deletions Firestore/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# 11.3.0
- [changed] Improve efficiency of memory persistence when processing a large number of writes. (#13572)
- [changed] Prepare Firestore cache to support session token.

# 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"

using firebase::firestore::nanopb::ByteString;

namespace firebase {
namespace firestore {
namespace local {

/**
* 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 name of the global value.
*/
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 name of global value.
*/
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 name that serves as identifier for global value for this entry. */
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

0 comments on commit 2893101

Please sign in to comment.