Skip to content
Open
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
32 changes: 32 additions & 0 deletions src/PackedEvent.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <bit>
#include <cstring>
#include <string_view>

#include "golpe.h"
Expand All @@ -18,6 +20,36 @@
// 1: length (1)
// 2: value (variable)

// Fixed-header layout used by the --fried import/export byte-swapper below.
static constexpr size_t PACKED_EVENT_HEADER_SIZE = 88;
static constexpr size_t PACKED_EVENT_CREATED_AT_OFF = 64;
static constexpr size_t PACKED_EVENT_KIND_OFF = 72;
static constexpr size_t PACKED_EVENT_EXPIRATION_OFF = 80;

// Byte-swap the three uint64_t fields (created_at, kind, expiration) in the
// fixed header of a packed event between native byte order and little-endian.
// The --fried wire format is defined as always little-endian, so callers on
// big-endian systems invoke this to serialise/deserialise.
//
// On little-endian hosts this is a compile-time no-op (the whole body is
// discarded by `if constexpr`), giving zero runtime cost on x86/ARM-LE.
//
// Callers must ensure `packed.size() >= PACKED_EVENT_HEADER_SIZE` before
// invoking this — untrusted input (e.g. hex-decoded from an imported file)
// may be shorter.
inline void friedSwapEndianInPlace(std::string &packed) {
if constexpr (std::endian::native != std::endian::little) {
for (size_t offset : {PACKED_EVENT_CREATED_AT_OFF, PACKED_EVENT_KIND_OFF, PACKED_EVENT_EXPIRATION_OFF}) {
uint64_t val;
std::memcpy(&val, packed.data() + offset, 8);
val = __builtin_bswap64(val);
std::memcpy(packed.data() + offset, &val, 8);
}
} else {
(void)packed;
}
}

struct PackedEventView {
std::string_view buf;

Expand Down
10 changes: 7 additions & 3 deletions src/apps/dbutils/cmd_export.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include <iostream>
#include <cstring>

#include <docopt.h>
#include "golpe.h"

#include "events.h"
#include "PackedEvent.h"


static const char USAGE[] =
Expand Down Expand Up @@ -31,7 +33,6 @@ void cmd_export(const std::vector<std::string> &subArgs) {
if (dbVersion == 0) throw herr("migration from DB version 0 not supported by this version of strfry");

if (fried) {
if (std::endian::native != std::endian::little) throw herr("--fried currently only supported on little-endian CPUs"); // FIXME
if (dbVersion < 3) throw herr("can't export old DB version with --fried: please downgrade to 0.9.7");
}

Expand All @@ -54,13 +55,16 @@ void cmd_export(const std::vector<std::string> &subArgs) {

if (fried) {
auto ev = lookupEventByLevId(txn, levId);
std::string packed(ev.buf);
// Events produced by strfry always have the full fixed header; no bounds check needed on export path.
friedSwapEndianInPlace(packed);

o.clear();
o.reserve(json.size() + ev.buf.size() * 2 + 100);
o.reserve(json.size() + packed.size() * 2 + 100);
o = json;
o.resize(o.size() - 1);
o += ",\"fried\":\"";
o += to_hex(ev.buf);
o += to_hex(packed);
o += "\"}\n";

std::cout << o;
Expand Down
6 changes: 4 additions & 2 deletions src/apps/dbutils/cmd_import.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <cstring>

#include <iostream>

#include <docopt.h>
#include "golpe.h"

#include "PackedEvent.h"
#include "WriterPipeline.h"


Expand All @@ -29,6 +31,8 @@ EventToWrite parseFried(std::string_view lineSv) {
if (!std::string_view(line).substr(0, i + 1).ends_with(",\"fried\":\"")) throw herr("fried parse error");

std::string packed = from_hex(std::string_view(line).substr(i + 1, line.size() - i - 3));
if (packed.size() < PACKED_EVENT_HEADER_SIZE) throw herr("fried packed too short");
friedSwapEndianInPlace(packed);

line[i - 9] = '}';
line.resize(i - 8);
Expand Down Expand Up @@ -76,8 +80,6 @@ void cmd_import(const std::vector<std::string> &subArgs) {
std::string_view line(buf, (size_t)numRead-1);

if (fried) {
if (std::endian::native != std::endian::little) throw herr("--fried currently only supported on little-endian CPUs"); // FIXME

try {
writer.write(parseFried(line));
} catch (std::exception &e) {
Expand Down
Loading