Include title in indexes to avoid a per-record disk read

GOTTA GO FAST
custom
jacqueline 2 years ago
parent 67ab8bf515
commit df22bed072
  1. 2
      src/app_console/app_console.cpp
  2. 26
      src/database/database.cpp
  3. 7
      src/database/include/database.hpp
  4. 9
      src/database/index.cpp
  5. 7
      src/ui/screen_track_browser.cpp
  6. 2
      src/ui/ui_fsm.cpp

@ -259,7 +259,7 @@ int CmdDbIndex(int argc, char** argv) {
for (database::IndexRecord r : res->values()) { for (database::IndexRecord r : res->values()) {
std::cout << r.text().value_or("<unknown>"); std::cout << r.text().value_or("<unknown>");
if (r.track()) { if (r.track()) {
std::cout << "\t(id:" << r.track()->data().id() << ")"; std::cout << "\t(id:" << *r.track() << ")";
} }
std::cout << std::endl; std::cout << std::endl;
} }

@ -600,20 +600,12 @@ auto Database::ParseRecord<IndexRecord>(const leveldb::Slice& key,
return {}; return {};
} }
// If there was a track id included for this key, then this is a leaf record. std::optional<std::string> title;
// Fetch the actual track data instead of relying on the information in the if (!val.empty()) {
// key. title = val.ToString();
std::optional<Track> track;
if (data->track) {
std::optional<TrackData> track_data = dbGetTrackData(*data->track);
TrackTags track_tags;
if (track_data &&
tag_parser_->ReadAndParseTags(track_data->filepath(), &track_tags)) {
track.emplace(*track_data, track_tags);
}
} }
return IndexRecord(*data, track); return IndexRecord(*data, title, data->track);
} }
template <> template <>
@ -663,17 +655,17 @@ auto Database::ParseRecord<std::string>(const leveldb::Slice& key,
return stream.str(); return stream.str();
} }
IndexRecord::IndexRecord(const IndexKey& key, std::optional<Track> track) IndexRecord::IndexRecord(const IndexKey& key, std::optional<shared_string> title, std::optional<TrackId> track)
: key_(key), track_(track) {} : key_(key), override_text_(title), track_(track) {}
auto IndexRecord::text() const -> std::optional<shared_string> { auto IndexRecord::text() const -> std::optional<shared_string> {
if (track_) { if (override_text_) {
return track_->TitleOrFilename(); return override_text_;
} }
return key_.item; return key_.item;
} }
auto IndexRecord::track() const -> std::optional<Track> { auto IndexRecord::track() const -> std::optional<TrackId> {
return track_; return track_;
} }

@ -70,16 +70,17 @@ class Result {
class IndexRecord { class IndexRecord {
public: public:
explicit IndexRecord(const IndexKey&, std::optional<Track>); explicit IndexRecord(const IndexKey&, std::optional<shared_string>, std::optional<TrackId>);
auto text() const -> std::optional<shared_string>; auto text() const -> std::optional<shared_string>;
auto track() const -> std::optional<Track>; auto track() const -> std::optional<TrackId>;
auto Expand(std::size_t) const -> std::optional<Continuation<IndexRecord>>; auto Expand(std::size_t) const -> std::optional<Continuation<IndexRecord>>;
private: private:
IndexKey key_; IndexKey key_;
std::optional<Track> track_; std::optional<shared_string> override_text_;
std::optional<TrackId> track_;
}; };
class Database { class Database {

@ -52,15 +52,20 @@ auto Index(const IndexInfo& info, const Track& t, leveldb::WriteBatch* batch)
key.item = {}; key.item = {};
} }
// If this is the last component, then we should also fill in the track id. // If this is the last component, then we should also fill in the track id
// and title.
std::optional<std::string> title;
if (i == info.components.size() - 1) { if (i == info.components.size() - 1) {
key.track = t.data().id(); key.track = t.data().id();
if (info.components.at(i) != Tag::kTitle) {
title = t.TitleOrFilename();
}
} else { } else {
key.track = {}; key.track = {};
} }
auto encoded = EncodeIndexKey(key); auto encoded = EncodeIndexKey(key);
batch->Put(encoded.slice, leveldb::Slice{}); batch->Put(encoded.slice, title.value_or(""));
// If there are more components after this, then we need to finish by // If there are more components after this, then we need to finish by
// narrowing the header with the current title. // narrowing the header with the current title.

@ -110,7 +110,6 @@ auto TrackBrowser::Tick() -> void {
} }
if (loading_page_->wait_for(std::chrono::seconds(0)) == if (loading_page_->wait_for(std::chrono::seconds(0)) ==
std::future_status::ready) { std::future_status::ready) {
ESP_LOGI(kTag, "load finished. adding to page.");
auto result = loading_page_->get(); auto result = loading_page_->get();
AddResults(loading_pos_.value_or(END), result); AddResults(loading_pos_.value_or(END), result);
@ -125,12 +124,10 @@ auto TrackBrowser::OnItemSelected(lv_event_t* ev) -> void {
return; return;
} }
if (index < kPageBuffer) { if (index < kPageBuffer) {
ESP_LOGI(kTag, "fetch page at start");
FetchNewPage(START); FetchNewPage(START);
return; return;
} }
if (index > GetNumRecords() - kPageBuffer) { if (index > GetNumRecords() - kPageBuffer) {
ESP_LOGI(kTag, "fetch page at end");
FetchNewPage(END); FetchNewPage(END);
return; return;
} }
@ -254,7 +251,6 @@ auto TrackBrowser::DropPage(Position pos) -> void {
auto TrackBrowser::FetchNewPage(Position pos) -> void { auto TrackBrowser::FetchNewPage(Position pos) -> void {
if (loading_page_) { if (loading_page_) {
ESP_LOGI(kTag, "already loading; giving up");
return; return;
} }
@ -268,7 +264,6 @@ auto TrackBrowser::FetchNewPage(Position pos) -> void {
break; break;
} }
if (!cont) { if (!cont) {
ESP_LOGI(kTag, "out of pages; giving up");
return; return;
} }
@ -282,11 +277,9 @@ auto TrackBrowser::FetchNewPage(Position pos) -> void {
if (current_pages_.size() >= kMaxPages) { if (current_pages_.size() >= kMaxPages) {
switch (pos) { switch (pos) {
case START: case START:
ESP_LOGI(kTag, "dropping end page");
DropPage(END); DropPage(END);
break; break;
case END: case END:
ESP_LOGI(kTag, "dropping start page");
DropPage(START); DropPage(START);
break; break;
} }

@ -120,7 +120,7 @@ void Browse::react(const internal::RecordSelected& ev) {
ESP_LOGI(kTag, "selected track '%s'", ev.record.text()->c_str()); ESP_LOGI(kTag, "selected track '%s'", ev.record.text()->c_str());
// TODO(jacqueline): We should also send some kind of playlist info here. // TODO(jacqueline): We should also send some kind of playlist info here.
sQueue->Clear(); sQueue->Clear();
sQueue->AddLast(ev.record.track()->data().id()); sQueue->AddLast(*ev.record.track());
transit<Playing>(); transit<Playing>();
} else { } else {
ESP_LOGI(kTag, "selected record '%s'", ev.record.text()->c_str()); ESP_LOGI(kTag, "selected record '%s'", ev.record.text()->c_str());

Loading…
Cancel
Save