Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 50 additions & 62 deletions storage/dump/EmbeddingPropertyContainerLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,82 +42,70 @@ DumpResult<std::unique_ptr<PropertyContainer>> EmbeddingPropertyContainerLoader:
const uint64_t nullCount = it.get<uint64_t>();
const uint64_t nullPageCount = it.get<uint64_t>();

auto* container = new TypedPropertyContainer<types::Embedding>(dimension);
container->_ids.resize(propCount);

// Loading IDs
size_t offset = 0;
for (size_t i = 0; i < idPageCount; i++) {
_reader.nextPage();

if (_reader.errorOccured()) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS, _reader.error().value());
}

it = _reader.begin();
const size_t floatsPerPage = GraphDumpHelper::getCountPerPage<float>();

uint64_t floatCount = 0;
const bool floatCountOverflows = __builtin_mul_overflow(propCount, dimension, &floatCount);
const bool headerInvalid = (dimension == 0)
|| floatCountOverflows
|| (GraphDumpHelper::getPageCountForItems(floatCount, floatsPerPage) != floatPageCount);
if (headerInvalid) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS);
}

if (it.remainingBytes() != DumpConfig::PAGE_SIZE) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS);
}
std::unique_ptr<TypedPropertyContainer<types::Embedding>> container = std::make_unique<TypedPropertyContainer<types::Embedding>>(dimension);
container->_ids.resize(propCount);

const size_t countInPage = it.get<uint64_t>();
for (size_t j = 0; j < countInPage; j++) {
container->_ids[j + offset] = it.get<EntityID::Type>();
}
offset += countInPage;
if (auto res = GraphDumpHelper::loadPages(_reader, idPageCount, std::span {container->_ids}, DumpErrorType::COULD_NOT_READ_PROPS); !res) {
return res.get_unexpected();
}

// Loading float data — read flat floats and alloc into the container
std::vector<float> embeddingBuffer(dimension);
size_t floatOffset = 0;
std::vector<float> pageFloats(floatsPerPage);
std::vector<float> partialEmbedding(dimension);
size_t partialCount = 0;
size_t embeddingCount = 0;

for (size_t i = 0; i < floatPageCount; i++) {
_reader.nextPage();

if (_reader.errorOccured()) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS, _reader.error().value());
}

it = _reader.begin();

if (it.remainingBytes() != DumpConfig::PAGE_SIZE) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS);
size_t countInPage = 0;
if (auto res = GraphDumpHelper::loadPage(_reader, std::span {pageFloats}, countInPage, DumpErrorType::COULD_NOT_READ_PROPS); !res) {
return res.get_unexpected();
}

const size_t countInPage = it.get<uint64_t>();
for (size_t j = 0; j < countInPage; j++) {
const size_t bufIdx = floatOffset % dimension;
embeddingBuffer[bufIdx] = it.get<float>();
floatOffset++;

if (bufIdx == dimension - 1) {
container->_values.alloc(embeddingBuffer);
std::span<const float> remaining = std::span<const float> {pageFloats}.first(countInPage);
while (!remaining.empty()) {
if (embeddingCount == propCount) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS);
}
}
}

// Loading null ids
container->_nullIds.resize(nullCount);
offset = 0;

for (size_t i = 0; i < nullPageCount; i++) {
_reader.nextPage();
const size_t taken = std::min<size_t>(dimension - partialCount, remaining.size());
const bool wholeInPage = (partialCount == 0 && taken == dimension);

if (wholeInPage) {
container->_values.alloc(remaining.first(dimension));
embeddingCount++;
} else {
std::copy_n(remaining.begin(), taken, partialEmbedding.begin() + partialCount);
partialCount += taken;

if (partialCount == dimension) {
container->_values.alloc(partialEmbedding);
partialCount = 0;
embeddingCount++;
}
}

if (_reader.errorOccured()) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS, _reader.error().value());
remaining = remaining.subspan(taken);
}
}

it = _reader.begin();
if (embeddingCount != propCount) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS);
}

if (it.remainingBytes() != DumpConfig::PAGE_SIZE) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS);
}
container->_nullIds.resize(nullCount);

const size_t countInPage = it.get<uint64_t>();
for (size_t j = 0; j < countInPage; j++) {
container->_nullIds[j + offset] = it.get<EntityID::Type>();
}
offset += countInPage;
if (auto res = GraphDumpHelper::loadPages(_reader, nullPageCount, std::span {container->_nullIds}, DumpErrorType::COULD_NOT_READ_PROPS); !res) {
return res.get_unexpected();
}

// Reconstruct the entity ID -> index map. Nulls go in after the values, as sort()
Expand All @@ -136,5 +124,5 @@ DumpResult<std::unique_ptr<PropertyContainer>> EmbeddingPropertyContainerLoader:

container->_sorted = std::is_sorted(ids.begin(), ids.end());

return {std::unique_ptr<PropertyContainer> {container}};
return {std::unique_ptr<PropertyContainer> {container.release()}};
}
63 changes: 63 additions & 0 deletions storage/dump/GraphDumpHelper.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
#pragma once

#include <stdint.h>
#include <algorithm>
#include <charconv>
#include <span>
#include <type_traits>

#include "ID.h"
#include "DumpResult.h"
#include "FilePageWriter.h"
#include "FilePageReader.h"
#include "DumpConfig.h"
#include "FileReader.h"
#include "FileWriter.h"
Expand Down Expand Up @@ -46,6 +50,65 @@ class GraphDumpHelper {
}
}

template <typename T>
[[nodiscard]] static constexpr size_t getCountPerPage() {
return (DumpConfig::PAGE_SIZE - sizeof(uint64_t)) / sizeof(T);
}

template <typename T>
[[nodiscard]] static DumpResult<void> loadPage(fs::FilePageReader& reader,
std::span<T> out,
size_t& countInPage,
DumpErrorType errorType) {
static_assert(std::is_trivially_copyable_v<T>);

reader.nextPage();

if (reader.errorOccured()) {
return DumpError::result(errorType, reader.error().value());
}

fs::AlignedBufferIterator it = reader.begin();

if (it.remainingBytes() != DumpConfig::PAGE_SIZE) {
return DumpError::result(errorType);
}

const uint64_t count = it.get<uint64_t>();
const bool overflowsPage = count > getCountPerPage<T>();
const bool overflowsOut = count > out.size();
if (overflowsPage || overflowsOut) {
return DumpError::result(errorType);
}

std::copy_n(it.data(), count * sizeof(T), reinterpret_cast<uint8_t*>(out.data()));
countInPage = count;

return {};
}

template <typename T>
[[nodiscard]] static DumpResult<void> loadPages(fs::FilePageReader& reader,
size_t pageCount,
std::span<T> out,
DumpErrorType errorType) {
size_t offset = 0;
for (size_t i = 0; i < pageCount; i++) {
size_t countInPage = 0;
if (auto res = loadPage(reader, out.subspan(offset), countInPage, errorType); !res) {
return res;
}

offset += countInPage;
}

if (offset != out.size()) {
return DumpError::result(errorType);
}

return {};
}

static void writeFileHeader(fs::FilePageWriter& writer) {
writer.writeToCurrentPage(DumpConfig::ONE_BAD_CAFE);
writer.writeToCurrentPage(DumpConfig::VERSION);
Expand Down
69 changes: 8 additions & 61 deletions storage/dump/ListPropertyContainerLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,51 +45,17 @@ DumpResult<std::unique_ptr<PropertyContainer>> ListPropertyContainerLoader::load
const uint64_t nullCount = it.get<uint64_t>();
const uint64_t nullPageCount = it.get<uint64_t>();

auto* container = new TypedPropertyContainer<types::List>;
std::unique_ptr<TypedPropertyContainer<types::List>> container = std::make_unique<TypedPropertyContainer<types::List>>();
container->_ids.resize(propCount);

size_t offset = 0;
for (size_t i = 0; i < idPageCount; i++) {
_reader.nextPage();

if (_reader.errorOccured()) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS, _reader.error().value());
}

it = _reader.begin();

if (it.remainingBytes() != DumpConfig::PAGE_SIZE) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS);
}

const size_t countInPage = it.get<uint64_t>();
for (size_t j = 0; j < countInPage; j++) {
container->_ids[j + offset] = it.get<EntityID::Type>();
}
offset += countInPage;
if (auto res = GraphDumpHelper::loadPages(_reader, idPageCount, std::span {container->_ids}, DumpErrorType::COULD_NOT_READ_PROPS); !res) {
return res.get_unexpected();
}

std::vector<std::byte> stream(totalBytes);
size_t byteOffset = 0;

for (size_t i = 0; i < bytePageCount; i++) {
_reader.nextPage();

if (_reader.errorOccured()) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS, _reader.error().value());
}

it = _reader.begin();

if (it.remainingBytes() != DumpConfig::PAGE_SIZE) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS);
}

const size_t countInPage = it.get<uint64_t>();
for (size_t j = 0; j < countInPage; j++) {
stream[byteOffset + j] = std::byte {it.get<uint8_t>()};
}
byteOffset += countInPage;
if (auto res = GraphDumpHelper::loadPages(_reader, bytePageCount, std::span {stream}, DumpErrorType::COULD_NOT_READ_PROPS); !res) {
return res.get_unexpected();
}

ListContainer& values = container->_values;
Expand All @@ -115,28 +81,9 @@ DumpResult<std::unique_ptr<PropertyContainer>> ListPropertyContainerLoader::load
}

container->_nullIds.resize(nullCount);
offset = 0;

for (size_t i = 0; i < nullPageCount; i++) {
_reader.nextPage();

if (_reader.errorOccured()) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS, _reader.error().value());
}

it = _reader.begin();

if (it.remainingBytes() != DumpConfig::PAGE_SIZE) {
return DumpError::result(DumpErrorType::COULD_NOT_READ_PROPS);
}

const size_t countInPage = it.get<uint64_t>();

for (size_t j = 0; j < countInPage; j++) {
container->_nullIds[j + offset] = it.get<EntityID::Type>();
}

offset += countInPage;
if (auto res = GraphDumpHelper::loadPages(_reader, nullPageCount, std::span {container->_nullIds}, DumpErrorType::COULD_NOT_READ_PROPS); !res) {
return res.get_unexpected();
}

// Reconstruct the entity ID -> index map; it is not dumped. Nulls go in after the
Expand All @@ -155,5 +102,5 @@ DumpResult<std::unique_ptr<PropertyContainer>> ListPropertyContainerLoader::load

container->_sorted = std::is_sorted(ids.begin(), ids.end());

return {std::unique_ptr<PropertyContainer> {container}};
return {std::unique_ptr<PropertyContainer> {container.release()}};
}
Loading