ncm: content meta database cleanup

This commit is contained in:
Adubbz 2020-03-02 23:21:07 +11:00
parent 651ff2faa6
commit ef39627c26
3 changed files with 53 additions and 74 deletions

View file

@ -77,8 +77,7 @@ namespace ams::ncm {
Result GetContentMetaValuePointer(const ContentMetaHeader **out_value_ptr, size_t *out_size, const ContentMetaKey &key, const kvdb::MemoryKeyValueStore<ContentMetaKey> *kvs) {
R_TRY(GetContentMetaSize(out_size, key, kvs));
R_TRY(kvs->GetValuePointer(out_value_ptr, key));
return ResultSuccess();
return kvs->GetValuePointer(out_value_ptr, key);
}
}
@ -86,11 +85,10 @@ namespace ams::ncm {
Result ContentMetaDatabaseImpl::GetContentIdByTypeImpl(ContentId *out, const ContentMetaKey& key, ContentType type, std::optional<u8> id_offset) {
R_TRY(this->EnsureEnabled());
const auto it = this->kvs->lower_bound(key);
R_UNLESS(it != this->kvs->end(), ncm::ResultContentMetaNotFound());
R_UNLESS(it->GetKey().id == key.id, ncm::ResultContentMetaNotFound());
ContentMetaKeyValueStore::Entry *entry = nullptr;
R_TRY(this->FindContentMetaKeyValue(std::addressof(entry), key));
const auto stored_key = it->GetKey();
const auto stored_key = entry->GetKey();
const ContentMetaHeader *header = nullptr;
size_t value_size = 0;
@ -334,11 +332,11 @@ namespace ams::ncm {
R_TRY(this->EnsureEnabled());
R_UNLESS(this->kvs->GetCount() != 0, ncm::ResultContentMetaNotFound());
const auto it = this->kvs->lower_bound(key);
R_UNLESS(it != this->kvs->end(), ncm::ResultContentMetaNotFound());
R_UNLESS(it->GetKey() == key, ncm::ResultContentMetaNotFound());
ContentMetaKeyValueStore::Entry *entry = nullptr;
R_TRY(this->FindContentMetaKeyValue(std::addressof(entry), key));
out_size.SetValue(entry->GetValueSize());
out_size.SetValue(it->GetValueSize());
return ResultSuccess();
}
@ -350,10 +348,12 @@ namespace ams::ncm {
size_t value_size = 0;
R_TRY(GetContentMetaValuePointer(&value, &value_size, key, this->kvs));
/* Required system version is at the same offset for the patch and application extended header.
We use the application header for convenience. */
const auto ext_header = GetValueExtendedHeader<ApplicationMetaExtendedHeader>(value);
out_version.SetValue(ext_header->required_system_version);
if (key.type == ContentMetaType::Application) {
out_version.SetValue(GetValueExtendedHeader<ApplicationMetaExtendedHeader>(value)->required_system_version);
} else {
out_version.SetValue(GetValueExtendedHeader<PatchMetaExtendedHeader>(value)->required_system_version);
}
return ResultSuccess();
}
@ -364,9 +364,8 @@ namespace ams::ncm {
const ContentMetaHeader *value = nullptr;
size_t value_size = 0;
R_TRY(GetContentMetaValuePointer(&value, &value_size, key, this->kvs));
const auto ext_header = GetValueExtendedHeader<ApplicationMetaExtendedHeader>(value);
out_patch_id.SetValue(ext_header->patch_id);
out_patch_id.SetValue(GetValueExtendedHeader<ApplicationMetaExtendedHeader>(value)->patch_id);
return ResultSuccess();
}
@ -380,37 +379,30 @@ namespace ams::ncm {
R_UNLESS(out_orphaned.GetSize() >= content_ids.GetSize(), ncm::ResultBufferInsufficient());
/* Default to orphaned for all content ids. */
if (out_orphaned.GetSize() > 0) {
std::fill_n(out_orphaned.GetPointer(), out_orphaned.GetSize(), true);
for (size_t i = 0; i < out_orphaned.GetSize(); i++) {
out_orphaned[i] = true;
}
R_UNLESS(this->kvs->GetCount() != 0, ResultSuccess());
for (auto entry = this->kvs->begin(); entry != this->kvs->end(); entry++) {
const auto header = reinterpret_cast<const ContentMetaHeader *>(entry->GetValuePointer());
if (header->content_count == 0) {
continue;
}
if (content_ids.GetSize() == 0) {
continue;
}
const ContentInfo *content_infos = GetValueContentInfos(header);
for (size_t i = 0; i < header->content_count; i++) {
const ContentInfo *content_info = &content_infos[i];
/* Check if any of this entry's content infos matches one of the provided content ids.
If they do, then the content id isn't orphaned. */
for (size_t j = 0; j < content_ids.GetSize(); j++) {
const ContentId content_id = content_ids[j];
if (content_id == content_info->content_id) {
out_orphaned[j] = false;
break;
auto IsOrphanedContent = [](const sf::InArray<ContentId> &list, const ncm::ContentId &id) ALWAYS_INLINE_LAMBDA {
for (size_t i = 0; i < list.GetSize(); i++) {
if (list[i] == id) {
return std::make_optional(i);
}
}
return std::optional<size_t>(std::nullopt);
};
/* Check if any of this entry's content infos matches one of the content ids for lookup. */
/* If they do, then the content id isn't orphaned. */
for (size_t i = 0; i < header->content_count; i++) {
if (auto found = IsOrphanedContent(content_ids, content_infos[i].content_id); found) {
out_orphaned[*found] = false;
}
}
}
@ -420,8 +412,7 @@ namespace ams::ncm {
Result ContentMetaDatabaseImpl::Commit() {
R_TRY(this->EnsureEnabled());
R_TRY(this->kvs->Save());
R_TRY(fsdevCommitDevice(this->mount_name));
return ResultSuccess();
return fsdevCommitDevice(this->mount_name);
}
Result ContentMetaDatabaseImpl::HasContent(sf::Out<bool> out, const ContentMetaKey &key, ContentId content_id) {
@ -432,10 +423,8 @@ namespace ams::ncm {
if (header->content_count > 0) {
for (size_t i = 0; i < header->content_count; i++) {
const ContentInfo *content_info = &content_infos[i];
if (content_id == content_info->content_id) {
out.SetValue(false);
if (content_id == content_infos[i].content_id) {
out.SetValue(true);
return ResultSuccess();
}
}
@ -455,11 +444,6 @@ namespace ams::ncm {
const auto content_meta_infos = GetValueContentMetaInfos(header);
size_t entries_written = 0;
if (out_meta_info.GetSize() == 0) {
out_entries_written.SetValue(0);
return ResultSuccess();
}
for (size_t i = start_index; i < out_meta_info.GetSize(); i++) {
/* We have no more entries we can read out. */
if (header->content_meta_count <= start_index + i) {
@ -493,38 +477,31 @@ namespace ams::ncm {
/* As of 9.0.0, applications can be dependent on a specific base application version. */
if (hos::GetVersion() >= hos::Version_900 && key.type == ContentMetaType::Application) {
const auto ext_header = GetValueExtendedHeader<ApplicationMetaExtendedHeader>(value);
out_version.SetValue(ext_header->required_application_version);
out_version.SetValue(GetValueExtendedHeader<ApplicationMetaExtendedHeader>(value)->required_application_version);
return ResultSuccess();
}
R_UNLESS(key.type == ContentMetaType::AddOnContent, ncm::ResultInvalidContentMetaKey());
const auto ext_header = GetValueExtendedHeader<AddOnContentMetaExtendedHeader>(value);
out_version.SetValue(ext_header->required_application_version);
out_version.SetValue(GetValueExtendedHeader<AddOnContentMetaExtendedHeader>(value)->required_application_version);
return ResultSuccess();
}
Result ContentMetaDatabaseImpl::GetContentIdByTypeAndIdOffset(sf::Out<ContentId> out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) {
ContentId content_id;
R_TRY(this->GetContentIdByTypeImpl(&content_id, key, type, std::optional(id_offset)));
out_content_id.SetValue(content_id);
return ResultSuccess();
return this->GetContentIdByTypeImpl(out_content_id.GetPointer(), key, type, std::optional(id_offset));
}
Result ContentMetaDatabaseImpl::GetLatestProgram(ContentId *out_content_id, ProgramId program_id) {
ContentMetaKey key;
R_TRY(this->GetLatestContentMetaKey(&key, program_id));
R_TRY(this->GetContentIdByType(out_content_id, key, ContentType::Program));
return ResultSuccess();
return this->GetContentIdByType(out_content_id, key, ContentType::Program);
}
Result ContentMetaDatabaseImpl::GetLatestData(ContentId *out_content_id, ProgramId program_id) {
ContentMetaKey key;
R_TRY(this->GetLatestContentMetaKey(&key, program_id));
R_TRY(this->GetContentIdByType(out_content_id, key, ContentType::Data));
return ResultSuccess();
return this->GetContentIdByType(out_content_id, key, ContentType::Data);
}
}

View file

@ -23,10 +23,8 @@ namespace ams::ncm {
class ContentMetaDatabaseImpl : public ContentMetaDatabaseImplBase {
public:
ContentMetaDatabaseImpl(ams::kvdb::MemoryKeyValueStore<ContentMetaKey> *kvs, const char *mount_name) : ContentMetaDatabaseImplBase(kvs, mount_name) {
}
ContentMetaDatabaseImpl(ams::kvdb::MemoryKeyValueStore<ContentMetaKey> *kvs) : ContentMetaDatabaseImplBase(kvs) {
}
ContentMetaDatabaseImpl(ContentMetaKeyValueStore *kvs, const char *mount_name) : ContentMetaDatabaseImplBase(kvs, mount_name) { /* ... */ }
ContentMetaDatabaseImpl(ContentMetaKeyValueStore *kvs) : ContentMetaDatabaseImplBase(kvs) { /* ... */ }
private:
Result GetContentIdByTypeImpl(ContentId *out, const ContentMetaKey& key, ContentType type, std::optional<u8> id_offset);
Result GetLatestContentMetaKeyImpl(ContentMetaKey *out_key, ProgramId id);

View file

@ -23,19 +23,15 @@ namespace ams::ncm {
NON_COPYABLE(ContentMetaDatabaseImplBase);
NON_MOVEABLE(ContentMetaDatabaseImplBase);
protected:
ams::kvdb::MemoryKeyValueStore<ContentMetaKey> *kvs;
using ContentMetaKeyValueStore = ams::kvdb::MemoryKeyValueStore<ContentMetaKey>;
protected:
ContentMetaKeyValueStore *kvs;
char mount_name[16];
bool disabled;
protected:
ContentMetaDatabaseImplBase(ams::kvdb::MemoryKeyValueStore<ContentMetaKey> *kvs) :
kvs(kvs), disabled(false)
{
/* ... */
}
ContentMetaDatabaseImplBase(ContentMetaKeyValueStore *kvs) : kvs(kvs), disabled(false) { /* ... */ }
ContentMetaDatabaseImplBase(ams::kvdb::MemoryKeyValueStore<ContentMetaKey> *kvs, const char *mount_name) :
ContentMetaDatabaseImplBase(kvs)
{
ContentMetaDatabaseImplBase(ContentMetaKeyValueStore *kvs, const char *mount_name) : ContentMetaDatabaseImplBase(kvs) {
std::strcpy(this->mount_name, mount_name);
}
protected:
@ -43,6 +39,14 @@ namespace ams::ncm {
R_UNLESS(!this->disabled, ncm::ResultInvalidContentMetaDatabase());
return ResultSuccess();
}
Result FindContentMetaKeyValue(ContentMetaKeyValueStore::Entry **out_entry, const ContentMetaKey &key) {
const auto it = this->kvs->lower_bound(key);
R_UNLESS(it != this->kvs->end(), ncm::ResultContentMetaNotFound());
R_UNLESS(it->GetKey().id == key.id, ncm::ResultContentMetaNotFound());
*out_entry = it;
return ResultSuccess();
}
};
}