blob: fcffbd642a81e124d05af93eb92fe23791988e57 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ledger/bin/storage/impl/clock_serialization.h"
#include <cstddef>
#include <map>
#include <optional>
#include <string>
#include <vector>
#include "src/ledger/bin/storage/impl/clock_generated.h"
#include "src/ledger/bin/storage/impl/commit_serialization.h"
#include "src/ledger/bin/storage/public/constants.h"
#include "src/ledger/bin/storage/public/types.h"
#include "src/ledger/lib/convert/convert.h"
#include "third_party/abseil-cpp/absl/base/attributes.h"
#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h"
namespace storage {
namespace {
std::optional<flatbuffers::Offset<DeviceClockStorage>> SerializeDeviceClock(
flatbuffers::FlatBufferBuilder* buffer, const clocks::DeviceId& device_id,
const DeviceEntry& device_entry) {
auto device_id_storage = CreateDeviceIdStorage(
*buffer, convert::ToFlatBufferVector(buffer, device_id.fingerprint), device_id.epoch);
flatbuffers::Offset<CommitIdAndGenerationStorage> head_storage =
CreateCommitIdAndGenerationStorage(*buffer, ToIdStorage(device_entry.head.commit_id),
device_entry.head.generation);
flatbuffers::Offset<CommitIdAndGenerationStorage> cloud_storage;
if (device_entry.cloud) {
cloud_storage = CreateCommitIdAndGenerationStorage(
*buffer, ToIdStorage(device_entry.cloud->commit_id), device_entry.cloud->generation);
}
return CreateDeviceClockStorage(
*buffer, device_id_storage, DeviceEntryUnion_DeviceEntryStorage,
CreateDeviceEntryStorage(*buffer, head_storage, cloud_storage).Union());
}
std::optional<flatbuffers::Offset<DeviceClockStorage>> SerializeDeviceClock(
flatbuffers::FlatBufferBuilder* buffer, const clocks::DeviceId& device_id,
const ClockTombstone& /*tombstone_entry*/) {
auto device_id_storage = CreateDeviceIdStorage(
*buffer, convert::ToFlatBufferVector(buffer, device_id.fingerprint), device_id.epoch);
return CreateDeviceClockStorage(*buffer, device_id_storage, DeviceEntryUnion_Tombstone,
CreateTombstone(*buffer).Union());
}
std::optional<flatbuffers::Offset<DeviceClockStorage>> SerializeDeviceClock(
flatbuffers::FlatBufferBuilder* /*buffer*/, const clocks::DeviceId& /*device_id*/,
const ClockDeletion& /*tombstone_entry*/) {
return std::nullopt;
}
} // namespace
std::string SerializeDeviceId(const clocks::DeviceId& device_id) {
flatbuffers::FlatBufferBuilder buffer;
auto storage = CreateDeviceIdStorage(
buffer, convert::ToFlatBufferVector(&buffer, device_id.fingerprint), device_id.epoch);
buffer.Finish(storage);
return convert::ToString(buffer);
}
// Extracts a clocks::DeviceId from storage.
ABSL_MUST_USE_RESULT bool ExtractDeviceIdFromStorage(std::string data,
clocks::DeviceId* device_id) {
flatbuffers::Verifier verifier(reinterpret_cast<const unsigned char*>(data.data()), data.size());
if (!verifier.VerifyBuffer<DeviceIdStorage>(nullptr)) {
return false;
}
const DeviceIdStorage* storage =
flatbuffers::GetRoot<DeviceIdStorage>(reinterpret_cast<const unsigned char*>(data.data()));
if (!storage || !storage->Verify(verifier) || !storage->fingerprint()) {
return false;
}
device_id->fingerprint = convert::ToString(storage->fingerprint());
device_id->epoch = storage->epoch();
return true;
}
std::string SerializeClock(const Clock& clock) {
flatbuffers::FlatBufferBuilder buffer;
std::vector<flatbuffers::Offset<DeviceClockStorage>> device_clocks;
for (const auto& [device_id, device_entry] : clock) {
std::visit(
[&buffer, &device_clocks, device_id = device_id](const auto& e) {
auto device_clock = SerializeDeviceClock(&buffer, device_id, e);
if (device_clock) {
device_clocks.push_back(*device_clock);
}
},
device_entry);
}
auto storage = CreateClockStorage(buffer, buffer.CreateVector(device_clocks));
buffer.Finish(storage);
return convert::ToString(buffer);
}
bool ExtractClockFromStorage(std::string data, Clock* clock) {
flatbuffers::Verifier verifier(reinterpret_cast<const unsigned char*>(data.data()), data.size());
if (!VerifyClockStorageBuffer(verifier)) {
return false;
}
const ClockStorage* clock_storage =
GetClockStorage(reinterpret_cast<const unsigned char*>(data.data()));
if (!clock_storage || !clock_storage->Verify(verifier) || !clock_storage->devices()) {
return false;
}
clock->clear();
for (const auto& device_clock_storage : *clock_storage->devices()) {
clocks::DeviceId device_id;
if (!device_clock_storage->Verify(verifier) || !device_clock_storage->device_id() ||
!device_clock_storage->device_id()->fingerprint()) {
return false;
}
device_id.fingerprint = convert::ToString(device_clock_storage->device_id()->fingerprint());
device_id.epoch = device_clock_storage->device_id()->epoch();
switch (device_clock_storage->device_entry_type()) {
case DeviceEntryUnion_DeviceEntryStorage: {
const auto* device_entry_storage =
static_cast<const DeviceEntryStorage*>(device_clock_storage->device_entry());
if (!device_entry_storage || !device_entry_storage->Verify(verifier) ||
!device_entry_storage->head() || !device_entry_storage->head()->commit_id()) {
return false;
}
DeviceEntry device_entry;
device_entry.head.commit_id =
convert::ToString(ToCommitIdView(device_entry_storage->head()->commit_id()));
device_entry.head.generation = device_entry_storage->head()->generation();
if (device_entry_storage->cloud()) {
if (!device_entry_storage->cloud()->commit_id()) {
return false;
}
device_entry.cloud = {
convert::ToString(ToCommitIdView(device_entry_storage->cloud()->commit_id())),
device_entry_storage->cloud()->generation()};
}
clock->emplace(std::move(device_id), std::move(device_entry));
break;
}
case DeviceEntryUnion_Tombstone: {
clock->emplace(std::move(device_id), ClockTombstone());
break;
}
case DeviceEntryUnion_NONE:
// Should not happen.
return false;
}
}
return true;
}
} // namespace storage