1
0
Fork 0
forked from dlang/cdcdb

Сжатие для БД вынесено в параметр

This commit is contained in:
Alexander Zhirov 2025-09-13 00:30:29 +03:00
parent 8a9142234e
commit d93dc4d81b
Signed by: alexander
GPG key ID: C8D8BE544A27C511
3 changed files with 103 additions and 24 deletions

View file

@ -2,49 +2,87 @@ module cdcdb.snapshot;
import cdcdb.dblite; import cdcdb.dblite;
import zstd : uncompress;
import std.digest.sha : SHA256, digest, SHA256Digest;
import std.datetime : DateTime;
import std.exception : enforce; import std.exception : enforce;
final class Snapshot { final class Snapshot
{
private: private:
DBLite _db; DBLite _db;
DBSnapshot _snapshot; DBSnapshot _snapshot;
public: public:
this(DBLite dblite, DBSnapshot dbSnapshot) { this(DBLite dblite, DBSnapshot dbSnapshot)
{
_db = dblite; _db = dblite;
_snapshot = dbSnapshot; _snapshot = dbSnapshot;
} }
this(DBLite dblite, long idSnapshot) { this(DBLite dblite, long idSnapshot)
{
_db = dblite; _db = dblite;
_snapshot = _db.getSnapshot(idSnapshot); _snapshot = _db.getSnapshot(idSnapshot);
} }
ubyte[] data() { ubyte[] data()
auto dataChunks = _db.getChunks(_snapshot.id); {
auto chunks = _db.getChunks(_snapshot.id);
ubyte[] content; ubyte[] content;
import zstd : uncompress; foreach (chunk; chunks)
{
foreach (chunk; dataChunks) {
ubyte[] bytes; ubyte[] bytes;
if (chunk.zstd) { if (chunk.zstd)
{
enforce(chunk.zSize == chunk.content.length, "Размер сжатого фрагмента не соответствует ожидаемому"); enforce(chunk.zSize == chunk.content.length, "Размер сжатого фрагмента не соответствует ожидаемому");
bytes = cast(ubyte[]) uncompress(chunk.content); bytes = cast(ubyte[]) uncompress(chunk.content);
} else { }
else
{
bytes = chunk.content; bytes = chunk.content;
} }
enforce(chunk.size == bytes.length, "Оригинальный размер не соответствует ожидаемому"); enforce(chunk.size == bytes.length, "Оригинальный размер не соответствует ожидаемому");
enforce(chunk.sha256 == digest!SHA256(bytes), "Хеш-сумма фрагмента не совпадает");
content ~= bytes; content ~= bytes;
} }
import std.digest.sha : SHA256, digest;
enforce(_snapshot.sha256 == digest!SHA256(content), "Хеш-сумма файла не совпадает"); enforce(_snapshot.sha256 == digest!SHA256(content), "Хеш-сумма файла не совпадает");
return content; return content;
} }
bool remove() { void data(void delegate(const(ubyte)[]) sink)
{
auto chunks = _db.getChunks(_snapshot.id);
auto fctx = new SHA256Digest();
foreach (chunk; chunks)
{
ubyte[] bytes;
if (chunk.zstd)
{
enforce(chunk.zSize == chunk.content.length, "Размер сжатого фрагмента не соответствует ожидаемому");
bytes = cast(ubyte[]) uncompress(chunk.content);
}
else
{
bytes = chunk.content;
}
enforce(chunk.size == bytes.length, "Оригинальный размер не соответствует ожидаемому");
enforce(chunk.sha256 == digest!SHA256(bytes), "Хеш-сумма фрагмента не совпадает");
sink(bytes);
fctx.put(bytes);
}
enforce(_snapshot.sha256 = fctx.finish(), "Хеш-сумма файла не совпадает");
}
bool remove()
{
_db.beginImmediate(); _db.beginImmediate();
bool ok; bool ok;
@ -65,4 +103,40 @@ public:
return _snapshot.id == idDeleted; return _snapshot.id == idDeleted;
} }
@property long id() const nothrow @safe
{
return _snapshot.id;
}
@property string label() const @safe
{
return _snapshot.label;
}
@property DateTime created() const @safe
{
return _snapshot.createdUtc;
}
@property long length() const nothrow @safe
{
return _snapshot.sourceLength;
}
@property ubyte[32] sha256() const nothrow @safe
{
return _snapshot.sha256;
}
@property string status() const
{
import std.conv : to;
return _snapshot.status.to!string;
}
@property string description() const nothrow @safe
{
return _snapshot.description;
}
} }

View file

@ -4,12 +4,15 @@ import cdcdb.dblite;
import cdcdb.core; import cdcdb.core;
import cdcdb.snapshot; import cdcdb.snapshot;
import zstd : compress, Level;
final class Storage final class Storage
{ {
private: private:
// Параметры работы с базой данных // Параметры работы с базой данных
DBLite _db; DBLite _db;
bool _zstd; bool _zstd;
int _level;
// Настройки CDC механизма // Настройки CDC механизма
CDC _cdc; CDC _cdc;
size_t _minSize; size_t _minSize;
@ -31,10 +34,11 @@ private:
} }
public: public:
this(string database, bool zstd = false, size_t busyTimeout = 3000, size_t maxRetries = 3) this(string database, bool zstd = false, int level = Level.base, size_t busyTimeout = 3000, size_t maxRetries = 3)
{ {
_db = new DBLite(database, busyTimeout, maxRetries); _db = new DBLite(database, busyTimeout, maxRetries);
_zstd = zstd; _zstd = zstd;
_level = level;
initCDC(); initCDC();
} }
@ -94,8 +98,6 @@ public:
// Разбить на фрагменты // Разбить на фрагменты
Chunk[] chunks = _cdc.split(data); Chunk[] chunks = _cdc.split(data);
import zstd : compress;
// Запись фрагментов в БД // Запись фрагментов в БД
foreach (chunk; chunks) foreach (chunk; chunks)
{ {
@ -105,7 +107,7 @@ public:
auto content = data[chunk.offset .. chunk.offset + chunk.size]; auto content = data[chunk.offset .. chunk.offset + chunk.size];
if (_zstd) { if (_zstd) {
ubyte[] zBytes = compress(content, 22); ubyte[] zBytes = compress(content, _level);
size_t zSize = zBytes.length; size_t zSize = zBytes.length;
ubyte[32] zHash = digest!SHA256(zBytes); ubyte[32] zHash = digest!SHA256(zBytes);

View file

@ -2,11 +2,14 @@ import std.stdio;
import cdcdb; import cdcdb;
import std.file : read; import std.file : read, write;
import std.stdio : File, writeln;
import std.conv : to;
void main() void main()
{ {
auto storage = new Storage("/tmp/base.db", true); auto storage = new Storage("/tmp/base.db", true, 22);
storage.newSnapshot("/tmp/text", cast(ubyte[]) read("/tmp/text")); storage.newSnapshot("/tmp/text", cast(ubyte[]) read("/tmp/text"));
// if (snapshot !is null) { // if (snapshot !is null) {
@ -14,11 +17,11 @@ void main()
// snapshot.remove(); // snapshot.remove();
// } // }
import std.stdio : writeln;
foreach (snapshot; storage.getSnapshots()) { foreach (snapshot; storage.getSnapshots()) {
writeln(cast(string) snapshot.data); auto file = File("/tmp/restore" ~ snapshot.id.to!string, "wb");
snapshot.data((const(ubyte)[] content) {
file.rawWrite(content);
});
file.close();
} }
// writeln(cas.getVersion);
} }