summaryrefslogtreecommitdiff
path: root/src/database/include
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-12-07 16:57:05 +1100
committerjacqueline <me@jacqueline.id.au>2023-12-07 17:00:30 +1100
commit3f7f199cb940c8d5f6d48f77fd59971adffe49ef (patch)
treeaa22162e46c5e9ccce4c7ee8537b493f437664d9 /src/database/include
parent009f69c929eb1d1b65d75b0937fbf3b8de5d9148 (diff)
downloadtangara-fw-3f7f199cb940c8d5f6d48f77fd59971adffe49ef.tar.gz
Remove pre-iterator concepts
- No more IndexRecord/Result/dbGetPage nonsense - Queue is just track ids - i am so tired and have so much to do
Diffstat (limited to 'src/database/include')
-rw-r--r--src/database/include/database.hpp229
-rw-r--r--src/database/include/file_gatherer.hpp8
-rw-r--r--src/database/include/tag_parser.hpp14
-rw-r--r--src/database/include/track.hpp2
4 files changed, 113 insertions, 140 deletions
diff --git a/src/database/include/database.hpp b/src/database/include/database.hpp
index 327db3cb..c75dbf96 100644
--- a/src/database/include/database.hpp
+++ b/src/database/include/database.hpp
@@ -35,61 +35,18 @@
namespace database {
-struct Continuation {
- std::pmr::string prefix;
- std::pmr::string start_key;
- bool forward;
- bool was_prev_forward;
- size_t page_size;
-};
+struct SearchKey;
+class Record;
+class Iterator;
/*
- * Wrapper for a set of results from the database. Owns the list of results, as
- * well as a continuation token that can be used to continue fetching more
- * results if they were paginated.
+ * Handle to an open database. This can be used to store large amounts of
+ * persistent data on the SD card, in a manner that can be retrieved later very
+ * quickly.
+ *
+ * A database includes a number of 'indexes'. Each index is a sorted,
+ * hierarchical view of all the playable tracks on the device.
*/
-template <typename T>
-class Result {
- public:
- auto values() const -> const std::vector<std::shared_ptr<T>>& {
- return values_;
- }
-
- auto next_page() -> std::optional<Continuation>& { return next_page_; }
- auto prev_page() -> std::optional<Continuation>& { return prev_page_; }
-
- Result(const std::vector<std::shared_ptr<T>>&& values,
- std::optional<Continuation> next,
- std::optional<Continuation> prev)
- : values_(values), next_page_(next), prev_page_(prev) {}
-
- Result(const Result&) = delete;
- Result& operator=(const Result&) = delete;
-
- private:
- std::vector<std::shared_ptr<T>> values_;
- std::optional<Continuation> next_page_;
- std::optional<Continuation> prev_page_;
-};
-
-class IndexRecord {
- public:
- explicit IndexRecord(const IndexKey&,
- std::optional<std::pmr::string>,
- std::optional<TrackId>);
-
- auto text() const -> std::optional<std::pmr::string>;
- auto track() const -> std::optional<TrackId>;
-
- auto Expand(std::size_t) const -> std::optional<Continuation>;
- auto ExpandHeader() const -> IndexKey::Header;
-
- private:
- IndexKey key_;
- std::optional<std::pmr::string> override_text_;
- std::optional<TrackId> track_;
-};
-
class Database {
public:
enum DatabaseError {
@@ -106,31 +63,19 @@ class Database {
~Database();
- auto Put(const std::string& key, const std::string& val) -> void;
- auto Get(const std::string& key) -> std::optional<std::string>;
-
- auto Update() -> std::future<void>;
+ /* Adds an arbitrary record to the database. */
+ auto put(const std::string& key, const std::string& val) -> void;
- auto GetTrackPath(TrackId id) -> std::future<std::optional<std::pmr::string>>;
+ /* Retrives a value previously stored with `put`. */
+ auto get(const std::string& key) -> std::optional<std::string>;
- auto GetTrack(TrackId id) -> std::future<std::shared_ptr<Track>>;
+ auto getTrackPath(TrackId id) -> std::optional<std::string>;
+ auto getTrack(TrackId id) -> std::shared_ptr<Track>;
- /*
- * Fetches data for multiple tracks more efficiently than multiple calls to
- * GetTrack.
- */
- auto GetBulkTracks(std::vector<TrackId> id)
- -> std::future<std::vector<std::shared_ptr<Track>>>;
-
- auto GetIndexes() -> std::vector<IndexInfo>;
- auto GetTracksByIndex(IndexId index, std::size_t page_size)
- -> std::future<Result<IndexRecord>*>;
- auto GetTracks(std::size_t page_size) -> std::future<Result<Track>*>;
- auto GetDump(std::size_t page_size) -> std::future<Result<std::pmr::string>*>;
-
- template <typename T>
- auto GetPage(Continuation* c) -> std::future<Result<T>*>;
+ auto getIndexes() -> std::vector<IndexInfo>;
+ auto updateIndexes() -> void;
+ // Cannot be copied or moved.
Database(const Database&) = delete;
Database& operator=(const Database&) = delete;
@@ -157,106 +102,134 @@ class Database {
std::shared_ptr<tasks::Worker> worker);
auto dbMintNewTrackId() -> TrackId;
- auto dbEntomb(TrackId track, uint64_t hash) -> void;
+ auto dbEntomb(TrackId track, uint64_t hash) -> void;
auto dbPutTrackData(const TrackData& s) -> void;
auto dbGetTrackData(TrackId id) -> std::shared_ptr<TrackData>;
auto dbPutHash(const uint64_t& hash, TrackId i) -> void;
auto dbGetHash(const uint64_t& hash) -> std::optional<TrackId>;
+
auto dbCreateIndexesForTrack(const Track& track) -> void;
auto dbRemoveIndexes(std::shared_ptr<TrackData>) -> void;
+
auto dbIngestTagHashes(const TrackTags&,
std::pmr::unordered_map<Tag, uint64_t>&) -> void;
auto dbRecoverTagsFromHashes(const std::pmr::unordered_map<Tag, uint64_t>&)
-> std::shared_ptr<TrackTags>;
- template <typename T>
- auto dbGetPage(const Continuation& c) -> Result<T>*;
+ auto getRecord(const SearchKey& c)
+ -> std::optional<std::pair<std::pmr::string, Record>>;
+ auto countRecords(const SearchKey& c) -> size_t;
+};
- auto dbCount(const Continuation& c) -> size_t;
+/*
+ * Container for the data needed to iterate through database records. This is a
+ * lower-level type that the higher-level iterators are built from; most users
+ * outside this namespace shouldn't need to work with continuations.
+ */
+struct SearchKey {
+ std::pmr::string prefix;
+ /* If not given, then iteration starts from `prefix`. */
+ std::optional<std::pmr::string> key;
+ int offset;
- template <typename T>
- auto ParseRecord(const leveldb::Slice& key, const leveldb::Slice& val)
- -> std::shared_ptr<T>;
+ auto startKey() const -> std::string_view;
};
-template <>
-auto Database::ParseRecord<IndexRecord>(const leveldb::Slice& key,
- const leveldb::Slice& val)
- -> std::shared_ptr<IndexRecord>;
-template <>
-auto Database::ParseRecord<Track>(const leveldb::Slice& key,
- const leveldb::Slice& val)
- -> std::shared_ptr<Track>;
-template <>
-auto Database::ParseRecord<std::pmr::string>(const leveldb::Slice& key,
- const leveldb::Slice& val)
- -> std::shared_ptr<std::pmr::string>;
-
/*
- * Utility for accessing a large set of database records, one record at a time.
+ * A record belonging to one of the database's indexes. This may either be a
+ * leaf record, containing a track id, or a branch record, containing a new
+ * Header to retrieve results at the next level of the index.
*/
-class Iterator {
+class Record {
public:
- static auto Parse(std::weak_ptr<Database>, const cppbor::Array&)
- -> std::optional<Iterator>;
+ Record(const IndexKey&, const leveldb::Slice&);
- Iterator(std::weak_ptr<Database>, const IndexInfo&);
- Iterator(std::weak_ptr<Database>, const Continuation&);
- Iterator(const Iterator&);
+ Record(const Record&) = default;
+ Record& operator=(const Record& other) = default;
- Iterator& operator=(const Iterator& other);
+ auto text() const -> std::string_view;
+ auto contents() const -> const std::variant<TrackId, IndexKey::Header>&;
- auto database() const { return db_; }
+ private:
+ std::pmr::string text_;
+ std::variant<TrackId, IndexKey::Header> contents_;
+};
- using Callback = std::function<void(std::optional<IndexRecord>)>;
+/*
+ * Utility for accessing a large set of database records, one record at a time.
+ */
+class Iterator {
+ public:
+ Iterator(std::shared_ptr<Database>, IndexId);
+ Iterator(std::shared_ptr<Database>, const IndexKey::Header&);
- auto Next(Callback) -> void;
- auto NextSync() -> std::optional<IndexRecord>;
+ Iterator(const Iterator&) = default;
+ Iterator& operator=(const Iterator& other) = default;
- auto Prev(Callback) -> void;
+ auto value() const -> const std::optional<Record>&;
+ std::optional<Record> operator*() const { return value(); }
- auto PeekSync() -> std::optional<IndexRecord>;
+ auto next() -> void;
+ std::optional<Record> operator++() {
+ next();
+ return value();
+ }
+ std::optional<Record> operator++(int) {
+ auto val = value();
+ next();
+ return val;
+ }
- auto Size() const -> size_t;
+ auto prev() -> void;
+ std::optional<Record> operator--() {
+ prev();
+ return value();
+ }
+ std::optional<Record> operator--(int) {
+ auto val = value();
+ prev();
+ return val;
+ }
- auto cbor() const -> cppbor::Array&&;
+ auto count() const -> size_t;
private:
- Iterator(std::weak_ptr<Database>,
- std::optional<Continuation>&&,
- std::optional<Continuation>&&);
+ auto iterate(const SearchKey& key) -> void;
friend class TrackIterator;
- auto InvokeNull(Callback) -> void;
-
std::weak_ptr<Database> db_;
-
- std::mutex pos_mutex_;
- std::optional<Continuation> current_pos_;
- std::optional<Continuation> prev_pos_;
+ SearchKey key_;
+ std::optional<Record> current_;
};
class TrackIterator {
public:
- static auto Parse(std::weak_ptr<Database>, const cppbor::Array&)
- -> std::optional<TrackIterator>;
-
TrackIterator(const Iterator&);
- TrackIterator(const TrackIterator&);
- TrackIterator& operator=(TrackIterator&& other);
+ TrackIterator(const TrackIterator&) = default;
+ TrackIterator& operator=(TrackIterator&& other) = default;
+
+ auto value() const -> std::optional<TrackId>;
+ std::optional<TrackId> operator*() const { return value(); }
- auto Next() -> std::optional<TrackId>;
- auto Size() const -> size_t;
+ auto next() -> void;
+ std::optional<TrackId> operator++() {
+ next();
+ return value();
+ }
+ std::optional<TrackId> operator++(int) {
+ auto val = value();
+ next();
+ return val;
+ }
- auto cbor() const -> cppbor::Array&&;
+ auto count() const -> size_t;
private:
TrackIterator(std::weak_ptr<Database>);
-
- auto NextLeaf() -> void;
+ auto next(bool advance) -> void;
std::weak_ptr<Database> db_;
std::vector<Iterator> levels_;
diff --git a/src/database/include/file_gatherer.hpp b/src/database/include/file_gatherer.hpp
index 378727f7..66127bb7 100644
--- a/src/database/include/file_gatherer.hpp
+++ b/src/database/include/file_gatherer.hpp
@@ -20,16 +20,16 @@ class IFileGatherer {
virtual ~IFileGatherer(){};
virtual auto FindFiles(
- const std::pmr::string& root,
- std::function<void(const std::pmr::string&, const FILINFO&)> cb)
+ const std::string& root,
+ std::function<void(const std::string&, const FILINFO&)> cb)
-> void = 0;
};
class FileGathererImpl : public IFileGatherer {
public:
virtual auto FindFiles(
- const std::pmr::string& root,
- std::function<void(const std::pmr::string&, const FILINFO&)> cb)
+ const std::string& root,
+ std::function<void(const std::string&, const FILINFO&)> cb)
-> void override;
};
diff --git a/src/database/include/tag_parser.hpp b/src/database/include/tag_parser.hpp
index 04817c59..977c9afc 100644
--- a/src/database/include/tag_parser.hpp
+++ b/src/database/include/tag_parser.hpp
@@ -16,24 +16,24 @@ namespace database {
class ITagParser {
public:
virtual ~ITagParser() {}
- virtual auto ReadAndParseTags(const std::pmr::string& path)
+ virtual auto ReadAndParseTags(const std::string& path)
-> std::shared_ptr<TrackTags> = 0;
};
class GenericTagParser : public ITagParser {
public:
- auto ReadAndParseTags(const std::pmr::string& path)
+ auto ReadAndParseTags(const std::string& path)
-> std::shared_ptr<TrackTags> override;
};
class TagParserImpl : public ITagParser {
public:
TagParserImpl();
- auto ReadAndParseTags(const std::pmr::string& path)
+ auto ReadAndParseTags(const std::string& path)
-> std::shared_ptr<TrackTags> override;
private:
- std::map<std::pmr::string, std::unique_ptr<ITagParser>> extension_to_parser_;
+ std::map<std::string, std::unique_ptr<ITagParser>> extension_to_parser_;
GenericTagParser generic_parser_;
/*
@@ -43,14 +43,14 @@ class TagParserImpl : public ITagParser {
std::mutex cache_mutex_;
util::LruCache<16, std::pmr::string, std::shared_ptr<TrackTags>> cache_;
- // We could also consider keeping caches of artist name -> std::pmr::string
- // and similar. This hasn't been done yet, as this isn't a common workload in
+ // We could also consider keeping caches of artist name -> std::string and
+ // similar. This hasn't been done yet, as this isn't a common workload in
// any of our UI.
};
class OpusTagParser : public ITagParser {
public:
- auto ReadAndParseTags(const std::pmr::string& path)
+ auto ReadAndParseTags(const std::string& path)
-> std::shared_ptr<TrackTags> override;
};
diff --git a/src/database/include/track.hpp b/src/database/include/track.hpp
index 8a24024f..0497c94d 100644
--- a/src/database/include/track.hpp
+++ b/src/database/include/track.hpp
@@ -123,7 +123,7 @@ struct TrackData {
public:
TrackData()
: id(0),
- filepath(&memory::kSpiRamResource),
+ filepath(),
tags_hash(0),
individual_tag_hashes(&memory::kSpiRamResource),
is_tombstoned(false),