Files
scylladb/db/commitlog/commitlog_entry.hh
Calle Wilund e29bf6f9e8 commitlog: Implement new format using CRC:ed sectors
Breaks the file into individually tagged + crc:ed pages.
Each page (sized as disk write alignment) gets a trailing
12-byte metadata, including CRC of the first page-12 bytes,
and the ID of the segment being written.

When reading, each page read is CRC:ed and checked to be part
of the expected segment by comparing ID:s. If crc is broken,
we have broken data. If crc is ok, but ID does not match, we
have a prematurely terminated segment (truncated), which, depending
on whether we use batch mode or not, implied data loss.
2023-11-21 08:50:54 +00:00

139 lines
3.7 KiB
C++

/*
* Copyright 2016-present ScyllaDB
*/
/*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include <optional>
#include "commitlog_types.hh"
#include "mutation/frozen_mutation.hh"
#include "schema/schema_fwd.hh"
#include "replay_position.hh"
namespace detail {
using buffer_type = fragmented_temporary_buffer;
using base_iterator = typename std::vector<temporary_buffer<char>>::const_iterator;
static constexpr auto sector_overhead_size = sizeof(uint32_t) + sizeof(db::segment_id_type);
// iterator adaptor to enable splitting normal
// frag-buffer temporary buffer objects into
// sub-disk-page sized chunks.
class sector_split_iterator {
base_iterator _iter, _end;
char* _ptr;
size_t _size;
size_t _sector_size;
public:
sector_split_iterator(const sector_split_iterator&) noexcept;
sector_split_iterator(base_iterator i, base_iterator e, size_t sector_size);
sector_split_iterator();
char* get_write() const {
return _ptr;
}
size_t size() const {
return _size;
}
char* begin() {
return _ptr;
}
char* end() {
return _ptr + _size;
}
const char* begin() const {
return _ptr;
}
const char* end() const {
return _ptr + _size;
}
bool operator==(const sector_split_iterator& rhs) const {
return _iter == rhs._iter && _ptr == rhs._ptr;
}
auto& operator*() const {
return *this;
}
auto* operator->() const {
return this;
}
sector_split_iterator& operator++();
sector_split_iterator operator++(int);
};
}
class commitlog_entry {
std::optional<column_mapping> _mapping;
frozen_mutation _mutation;
public:
commitlog_entry(std::optional<column_mapping> mapping, frozen_mutation&& mutation)
: _mapping(std::move(mapping)), _mutation(std::move(mutation)) { }
const std::optional<column_mapping>& mapping() const { return _mapping; }
const frozen_mutation& mutation() const & { return _mutation; }
frozen_mutation&& mutation() && { return std::move(_mutation); }
};
class commitlog_entry_writer {
public:
using force_sync = db::commitlog_force_sync;
private:
schema_ptr _schema;
const frozen_mutation& _mutation;
bool _with_schema = true;
size_t _size = std::numeric_limits<size_t>::max();
force_sync _sync;
private:
template<typename Output>
void serialize(Output&) const;
void compute_size();
public:
commitlog_entry_writer(schema_ptr s, const frozen_mutation& fm, force_sync sync)
: _schema(std::move(s)), _mutation(fm), _sync(sync)
{}
void set_with_schema(bool value) {
_with_schema = value;
compute_size();
}
bool with_schema() const {
return _with_schema;
}
schema_ptr schema() const {
return _schema;
}
size_t size() const {
assert(_size != std::numeric_limits<size_t>::max());
return _size;
}
size_t mutation_size() const {
return _mutation.representation().size();
}
force_sync sync() const {
return _sync;
}
using ostream = typename seastar::memory_output_stream<detail::sector_split_iterator>;
void write(ostream& out) const;
};
class commitlog_entry_reader {
commitlog_entry _ce;
public:
commitlog_entry_reader(const fragmented_temporary_buffer& buffer);
const std::optional<column_mapping>& get_column_mapping() const { return _ce.mapping(); }
const frozen_mutation& mutation() const & { return _ce.mutation(); }
frozen_mutation&& mutation() && { return std::move(_ce).mutation(); }
};