forked from dlang/cdcdb
Сжатие для БД вынесено в параметр
This commit is contained in:
parent
8a9142234e
commit
d93dc4d81b
3 changed files with 103 additions and 24 deletions
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
17
test/app.d
17
test/app.d
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue