summaryrefslogtreecommitdiff
path: root/src/tangara/database
diff options
context:
space:
mode:
Diffstat (limited to 'src/tangara/database')
-rw-r--r--src/tangara/database/database.cpp56
-rw-r--r--src/tangara/database/database.hpp2
2 files changed, 42 insertions, 16 deletions
diff --git a/src/tangara/database/database.cpp b/src/tangara/database/database.cpp
index e3f3df67..c543b941 100644
--- a/src/tangara/database/database.cpp
+++ b/src/tangara/database/database.cpp
@@ -24,6 +24,7 @@
#include "cppbor.h"
#include "cppbor_parse.h"
#include "database/index.hpp"
+#include "debug.hpp"
#include "esp_log.h"
#include "esp_timer.h"
#include "ff.h"
@@ -60,7 +61,6 @@ static const char kKeyDbVersion[] = "schema_version";
static const char kKeyCustom[] = "U\0";
static const char kKeyCollator[] = "collator";
-static const char kKeyTrackId[] = "next_track_id";
static std::atomic<bool> sIsDbOpen(false);
@@ -190,7 +190,10 @@ Database::Database(leveldb::DB* db,
file_gatherer_(file_gatherer),
tag_parser_(tag_parser),
collator_(collator),
- is_updating_(false) {}
+ is_updating_(false) {
+ dbCalculateNextTrackId();
+ ESP_LOGI(kTag, "next track id is %lu", next_track_id_.load());
+}
Database::~Database() {
// Delete db_ first so that any outstanding background work finishes before
@@ -492,24 +495,45 @@ auto Database::isUpdating() -> bool {
return is_updating_;
}
-auto Database::dbMintNewTrackId() -> TrackId {
- TrackId next_id = 1;
- std::string val;
- auto status = db_->Get(leveldb::ReadOptions(), kKeyTrackId, &val);
- if (status.ok()) {
- next_id = BytesToTrackId(val).value_or(next_id);
- } else if (!status.IsNotFound()) {
- // TODO(jacqueline): Handle this more.
- ESP_LOGE(kTag, "failed to get next track id");
+auto Database::dbCalculateNextTrackId() -> void {
+ std::unique_ptr<leveldb::Iterator> it{
+ db_->NewIterator(leveldb::ReadOptions())};
+
+ // Track data entries are of the format 'D/trackid', where track ids are
+ // encoded as big-endian cbor types. They can therefore be compared through
+ // byte ordering, which means we can determine what the next id should be by
+ // looking at the larged track data record in the database.
+ std::string prefix = EncodeDataPrefix();
+ std::string prefixPlusOne = prefix;
+ prefixPlusOne[prefixPlusOne.size() - 1]++;
+
+ // Seek to just past the track data section.
+ it->Seek(prefixPlusOne);
+ if (!it->Valid()) {
+ next_track_id_ = 1;
+ return;
}
- if (!db_->Put(leveldb::WriteOptions(), kKeyTrackId,
- TrackIdToBytes(next_id + 1))
- .ok()) {
- ESP_LOGE(kTag, "failed to write next track id");
+ // Go back to the last track data record.
+ it->Prev();
+ if (!it->Valid() || !it->key().starts_with(prefix)) {
+ next_track_id_ = 1;
+ return;
}
- return next_id;
+ // Parse the track id back out of the key.
+ std::span<const char> key{it->key().data(), it->key().size()};
+ auto id_part = key.subspan(prefix.size());
+ if (id_part.empty()) {
+ next_track_id_ = 1;
+ return;
+ }
+
+ next_track_id_ = BytesToTrackId(id_part).value_or(0) + 1;
+}
+
+auto Database::dbMintNewTrackId() -> TrackId {
+ return next_track_id_++;
}
auto Database::dbEntomb(TrackId id, uint64_t hash) -> void {
diff --git a/src/tangara/database/database.hpp b/src/tangara/database/database.hpp
index c2e72568..2b385013 100644
--- a/src/tangara/database/database.hpp
+++ b/src/tangara/database/database.hpp
@@ -100,6 +100,7 @@ class Database {
locale::ICollator& collator_;
std::atomic<bool> is_updating_;
+ std::atomic<TrackId> next_track_id_;
Database(leveldb::DB* db,
leveldb::Cache* cache,
@@ -107,6 +108,7 @@ class Database {
ITagParser& tag_parser,
locale::ICollator& collator);
+ auto dbCalculateNextTrackId() -> void;
auto dbMintNewTrackId() -> TrackId;
auto dbEntomb(TrackId track, uint64_t hash) -> void;