Переход на другую библиотеку
This commit is contained in:
parent
1f50b21457
commit
0fc56e7c04
5 changed files with 180 additions and 148 deletions
2
dub.json
2
dub.json
|
|
@ -7,7 +7,7 @@
|
||||||
"license": "BSL-1.0",
|
"license": "BSL-1.0",
|
||||||
"name": "cdcdb",
|
"name": "cdcdb",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"arsd-official:sqlite": "~>12.0.0",
|
"d2sqlite3": "~>1.0.0",
|
||||||
"zstd": "~>0.2.1"
|
"zstd": "~>0.2.1"
|
||||||
},
|
},
|
||||||
"stringImportPaths": [
|
"stringImportPaths": [
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
"fileVersion": 1,
|
"fileVersion": 1,
|
||||||
"versions": {
|
"versions": {
|
||||||
"arsd-official": "12.0.0",
|
"arsd-official": "12.0.0",
|
||||||
|
"d2sqlite3": "1.0.0",
|
||||||
"zstd": "0.2.1"
|
"zstd": "0.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
module cdcdb.dblite;
|
module cdcdb.dblite;
|
||||||
|
|
||||||
import arsd.sqlite : Sqlite, SqliteResult, DatabaseException;
|
import d2sqlite3;
|
||||||
|
|
||||||
import std.string : join, replace, toLower;
|
import std.string : join, replace, toLower;
|
||||||
import std.algorithm : canFind;
|
import std.algorithm : canFind;
|
||||||
|
|
@ -91,19 +91,29 @@ struct DBSnapshotChunkData {
|
||||||
ubyte[32] zSha256; /// Хеш сжатого содержимого.
|
ubyte[32] zSha256; /// Хеш сжатого содержимого.
|
||||||
}
|
}
|
||||||
|
|
||||||
final class DBLite : Sqlite
|
final class DBLite
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
string _dbPath; /// Путь к файлу БД.
|
string _dbPath; /// Путь к файлу БД.
|
||||||
size_t _maxRetries; /// Максимум повторов при `busy/locked`.
|
size_t _maxRetries; /// Максимум повторов при `busy/locked`.
|
||||||
|
Database _db; /// Соединение с БД (d2sqlite3).
|
||||||
|
|
||||||
// SQL-схема (массив строковых запросов).
|
// SQL-схема (массив строковых запросов).
|
||||||
mixin(import("scheme.d"));
|
mixin(import("scheme.d"));
|
||||||
|
|
||||||
/// Выполняет SQL с повторными попытками при `locked/busy`.
|
/// Выполняет SQL с повторными попытками при `locked/busy`.
|
||||||
SqliteResult sql(T...)(string queryText, T args)
|
ResultRange sql(T...)(string queryText, T args)
|
||||||
{
|
{
|
||||||
|
// Готовим стейтмент сами, чтобы bindAll() работал и для BLOB.
|
||||||
|
auto attempt = () {
|
||||||
|
auto st = _db.prepare(queryText);
|
||||||
|
static if (T.length > 0)
|
||||||
|
st.bindAll(args);
|
||||||
|
return st.execute();
|
||||||
|
};
|
||||||
|
|
||||||
if (_maxRetries == 0) {
|
if (_maxRetries == 0) {
|
||||||
return cast(SqliteResult) query(queryText, args);
|
return attempt();
|
||||||
}
|
}
|
||||||
|
|
||||||
string msg;
|
string msg;
|
||||||
|
|
@ -111,10 +121,11 @@ private:
|
||||||
|
|
||||||
while (tryNo) {
|
while (tryNo) {
|
||||||
try {
|
try {
|
||||||
return cast(SqliteResult) query(queryText, args);
|
return attempt();
|
||||||
} catch (DatabaseException e) {
|
} catch (SqliteException e) {
|
||||||
msg = e.msg;
|
msg = e.msg;
|
||||||
if (msg.toLower.canFind("locked", "busy")) {
|
const code = e.code;
|
||||||
|
if (code == SQLITE_BUSY || code == SQLITE_LOCKED) {
|
||||||
if (--tryNo == 0) {
|
if (--tryNo == 0) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
"Не удалось выполнить запрос к базе данных после %d неудачных попыток: %s"
|
"Не удалось выполнить запрос к базе данных после %d неудачных попыток: %s"
|
||||||
|
|
@ -123,17 +134,18 @@ private:
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break; // другие ошибки — дальше по стеку
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Exception(msg);
|
// До сюда не дойдём, но для формальной полноты:
|
||||||
|
throw new Exception(msg.length ? msg : "SQLite error");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Проверяет наличие обязательных таблиц.
|
/// Проверяет наличие обязательных таблиц.
|
||||||
/// Если все отсутствуют — создаёт схему; если отсутствует часть — бросает ошибку.
|
/// Если все отсутствуют — создаёт схему; если отсутствует часть — бросает ошибку.
|
||||||
void check()
|
void check()
|
||||||
{
|
{
|
||||||
SqliteResult queryResult = sql(
|
auto queryResult = sql(
|
||||||
q{
|
q{
|
||||||
WITH required(name)
|
WITH required(name)
|
||||||
AS (VALUES ("snapshots"), ("blobs"), ("snapshot_chunks"), ("users"), ("processes"), ("files"))
|
AS (VALUES ("snapshots"), ("blobs"), ("snapshot_chunks"), ("users"), ("processes"), ("files"))
|
||||||
|
|
@ -151,7 +163,7 @@ private:
|
||||||
|
|
||||||
foreach (row; queryResult)
|
foreach (row; queryResult)
|
||||||
{
|
{
|
||||||
missingTables ~= row["missing_table"].to!string;
|
missingTables ~= row["missing_table"].as!string;
|
||||||
}
|
}
|
||||||
|
|
||||||
enforce(missingTables.length == 0 || missingTables.length == 6,
|
enforce(missingTables.length == 0 || missingTables.length == 6,
|
||||||
|
|
@ -171,16 +183,16 @@ public:
|
||||||
this(string database, size_t busyTimeout, size_t maxRetries)
|
this(string database, size_t busyTimeout, size_t maxRetries)
|
||||||
{
|
{
|
||||||
_dbPath = database;
|
_dbPath = database;
|
||||||
super(database);
|
_db = Database(database);
|
||||||
|
|
||||||
check();
|
check();
|
||||||
|
|
||||||
_maxRetries = maxRetries;
|
_maxRetries = maxRetries;
|
||||||
|
|
||||||
query("PRAGMA journal_mode=WAL");
|
_db.execute("PRAGMA journal_mode=WAL");
|
||||||
query("PRAGMA synchronous=NORMAL");
|
_db.execute("PRAGMA synchronous=NORMAL");
|
||||||
query("PRAGMA foreign_keys=ON");
|
_db.execute("PRAGMA foreign_keys=ON");
|
||||||
query("PRAGMA busy_timeout=%d".format(busyTimeout));
|
_db.execute("PRAGMA busy_timeout=%d".format(busyTimeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BEGIN IMMEDIATE.
|
/// BEGIN IMMEDIATE.
|
||||||
|
|
@ -192,13 +204,13 @@ public:
|
||||||
/// COMMIT.
|
/// COMMIT.
|
||||||
void commit()
|
void commit()
|
||||||
{
|
{
|
||||||
sql("COMMIT");
|
_db.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ROLLBACK.
|
/// ROLLBACK.
|
||||||
void rollback()
|
void rollback()
|
||||||
{
|
{
|
||||||
sql("ROLLBACK");
|
_db.rollback();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************
|
/*************************************************
|
||||||
|
|
@ -218,8 +230,8 @@ public:
|
||||||
{
|
{
|
||||||
DBFile file;
|
DBFile file;
|
||||||
|
|
||||||
file.id = cast(ubyte[]) row["id"].dup;
|
file.id = row["id"].as!Blob(Blob.init);
|
||||||
file.path = row["name"].to!string;
|
file.path = row["name"].as!string;
|
||||||
|
|
||||||
files ~= file;
|
files ~= file;
|
||||||
}
|
}
|
||||||
|
|
@ -236,10 +248,10 @@ public:
|
||||||
|
|
||||||
DBFile file;
|
DBFile file;
|
||||||
|
|
||||||
if (!queryResult.empty()) {
|
if (!queryResult.empty) {
|
||||||
auto data = queryResult.front();
|
auto data = queryResult.front;
|
||||||
|
|
||||||
file.id = cast(ubyte[]) data["id"].dup;
|
file.id = data["id"].as!Blob(Blob.init);
|
||||||
file.path = path;
|
file.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,18 +269,18 @@ public:
|
||||||
|
|
||||||
DBFile file;
|
DBFile file;
|
||||||
|
|
||||||
if (!queryResult.empty()) {
|
if (!queryResult.empty) {
|
||||||
auto data = queryResult.front();
|
auto data = queryResult.front;
|
||||||
|
|
||||||
file.id = id;
|
file.id = id;
|
||||||
file.path = data["name"].to!string;
|
file.path = data["name"].as!string;
|
||||||
}
|
}
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBFile addFile(string path) {
|
DBFile addFile(string path) {
|
||||||
SqliteResult queryResult;
|
ResultRange queryResult;
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
|
|
||||||
// Исключение одинакового UUID первичного ключа
|
// Исключение одинакового UUID первичного ключа
|
||||||
|
|
@ -279,7 +291,7 @@ public:
|
||||||
SELECT id FROM files WHERE id = ?1
|
SELECT id FROM files WHERE id = ?1
|
||||||
}, uuid.data[]
|
}, uuid.data[]
|
||||||
);
|
);
|
||||||
} while (!queryResult.empty());
|
} while (!queryResult.empty);
|
||||||
|
|
||||||
queryResult = sql(
|
queryResult = sql(
|
||||||
q{
|
q{
|
||||||
|
|
@ -289,7 +301,7 @@ public:
|
||||||
}, uuid.data[], path
|
}, uuid.data[], path
|
||||||
);
|
);
|
||||||
|
|
||||||
enforce(!queryResult.empty(), "Не удалось добавить новый файл в базу данных");
|
enforce(!queryResult.empty, "Не удалось добавить новый файл в базу данных");
|
||||||
|
|
||||||
return DBFile(Identifier(uuid.data), path);
|
return DBFile(Identifier(uuid.data), path);
|
||||||
}
|
}
|
||||||
|
|
@ -307,8 +319,8 @@ public:
|
||||||
{
|
{
|
||||||
DBFile file;
|
DBFile file;
|
||||||
|
|
||||||
file.id = cast(ubyte[]) row["id"].dup;
|
file.id = row["id"].as!Blob(Blob.init);
|
||||||
file.path = row["name"].to!string;
|
file.path = row["name"].as!string;
|
||||||
|
|
||||||
files ~= file;
|
files ~= file;
|
||||||
}
|
}
|
||||||
|
|
@ -339,8 +351,8 @@ public:
|
||||||
{
|
{
|
||||||
DBFile file;
|
DBFile file;
|
||||||
|
|
||||||
file.id = cast(ubyte[]) row["id"].dup;
|
file.id = row["id"].as!Blob(Blob.init);
|
||||||
file.path = row["name"].to!string;
|
file.path = row["name"].as!string;
|
||||||
|
|
||||||
files ~= file;
|
files ~= file;
|
||||||
}
|
}
|
||||||
|
|
@ -350,12 +362,12 @@ public:
|
||||||
|
|
||||||
bool deleteFile(Identifier id) {
|
bool deleteFile(Identifier id) {
|
||||||
auto queryResult = sql("DELETE FROM files WHERE id = ?1 RETURNING id", id[]);
|
auto queryResult = sql("DELETE FROM files WHERE id = ?1 RETURNING id", id[]);
|
||||||
return !queryResult.empty();
|
return !queryResult.empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deleteFile(string path) {
|
bool deleteFile(string path) {
|
||||||
auto queryResult = sql("DELETE FROM files WHERE name = ?1 RETURNING id", path);
|
auto queryResult = sql("DELETE FROM files WHERE name = ?1 RETURNING id", path);
|
||||||
return !queryResult.empty();
|
return !queryResult.empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -376,8 +388,8 @@ public:
|
||||||
}, id[], sha256[]
|
}, id[], sha256[]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!queryResult.empty())
|
if (!queryResult.empty)
|
||||||
return queryResult.front()["is_last"].to!long > 0;
|
return queryResult.front["is_last"].as!long > 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -393,7 +405,7 @@ public:
|
||||||
}, uid, name
|
}, uid, name
|
||||||
);
|
);
|
||||||
|
|
||||||
return !queryResult.empty();
|
return !queryResult.empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBProcess getProcess(string name) {
|
DBProcess getProcess(string name) {
|
||||||
|
|
@ -405,10 +417,10 @@ public:
|
||||||
|
|
||||||
DBProcess process;
|
DBProcess process;
|
||||||
|
|
||||||
if (!queryResult.empty()) {
|
if (!queryResult.empty) {
|
||||||
auto data = queryResult.front();
|
auto data = queryResult.front;
|
||||||
|
|
||||||
process.id = cast(ubyte[]) data["id"].dup;
|
process.id = data["id"].as!Blob(Blob.init);
|
||||||
process.name = name;
|
process.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -426,18 +438,18 @@ public:
|
||||||
|
|
||||||
DBProcess process;
|
DBProcess process;
|
||||||
|
|
||||||
if (!queryResult.empty()) {
|
if (!queryResult.empty) {
|
||||||
auto data = queryResult.front();
|
auto data = queryResult.front;
|
||||||
|
|
||||||
process.id = id;
|
process.id = id;
|
||||||
process.name = data["name"].to!string;
|
process.name = data["name"].as!string;
|
||||||
}
|
}
|
||||||
|
|
||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBProcess addProcess(string name) {
|
DBProcess addProcess(string name) {
|
||||||
SqliteResult queryResult;
|
ResultRange queryResult;
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
|
|
||||||
// Исключение одинакового UUID первичного ключа
|
// Исключение одинакового UUID первичного ключа
|
||||||
|
|
@ -448,7 +460,7 @@ public:
|
||||||
SELECT id FROM processes WHERE id = ?1
|
SELECT id FROM processes WHERE id = ?1
|
||||||
}, uuid.data[]
|
}, uuid.data[]
|
||||||
);
|
);
|
||||||
} while (!queryResult.empty());
|
} while (!queryResult.empty);
|
||||||
|
|
||||||
queryResult = sql(
|
queryResult = sql(
|
||||||
q{
|
q{
|
||||||
|
|
@ -458,7 +470,7 @@ public:
|
||||||
}, uuid.data[], name
|
}, uuid.data[], name
|
||||||
);
|
);
|
||||||
|
|
||||||
enforce(!queryResult.empty(), "Не удалось добавить новый файл в базу данных");
|
enforce(!queryResult.empty, "Не удалось добавить новый файл в базу данных");
|
||||||
|
|
||||||
return DBProcess(Identifier(uuid.data), name);
|
return DBProcess(Identifier(uuid.data), name);
|
||||||
}
|
}
|
||||||
|
|
@ -467,7 +479,7 @@ public:
|
||||||
|
|
||||||
bool addSnapshot(ref DBSnapshot snapshot)
|
bool addSnapshot(ref DBSnapshot snapshot)
|
||||||
{
|
{
|
||||||
SqliteResult queryResult;
|
ResultRange queryResult;
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
|
|
||||||
// Исключение одинакового UUID первичного ключа
|
// Исключение одинакового UUID первичного ключа
|
||||||
|
|
@ -478,7 +490,7 @@ public:
|
||||||
SELECT id FROM snapshots WHERE id = ?1
|
SELECT id FROM snapshots WHERE id = ?1
|
||||||
}, uuid.data[]
|
}, uuid.data[]
|
||||||
);
|
);
|
||||||
} while (!queryResult.empty());
|
} while (!queryResult.empty);
|
||||||
|
|
||||||
import std.datetime : Clock;
|
import std.datetime : Clock;
|
||||||
|
|
||||||
|
|
@ -524,7 +536,7 @@ public:
|
||||||
snapshot.status.to!int // ?15
|
snapshot.status.to!int // ?15
|
||||||
);
|
);
|
||||||
|
|
||||||
return !queryResult.empty();
|
return !queryResult.empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -564,7 +576,7 @@ public:
|
||||||
blob.zstd.to!int // ?8
|
blob.zstd.to!int // ?8
|
||||||
);
|
);
|
||||||
|
|
||||||
return !queryResult.empty();
|
return !queryResult.empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool addSnapshotChunk(DBSnapshotChunk snapshotChunk)
|
bool addSnapshotChunk(DBSnapshotChunk snapshotChunk)
|
||||||
|
|
@ -581,7 +593,7 @@ public:
|
||||||
snapshotChunk.sha256[]
|
snapshotChunk.sha256[]
|
||||||
);
|
);
|
||||||
|
|
||||||
return !queryResult.empty();
|
return !queryResult.empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBSnapshotChunkData[] getChunks(Identifier id)
|
DBSnapshotChunkData[] getChunks(Identifier id)
|
||||||
|
|
@ -603,14 +615,22 @@ public:
|
||||||
{
|
{
|
||||||
DBSnapshotChunkData sdch;
|
DBSnapshotChunkData sdch;
|
||||||
|
|
||||||
sdch.chunkIndex = row["chunk_index"].to!long;
|
sdch.chunkIndex = row["chunk_index"].as!long;
|
||||||
sdch.offset = row["offset"].to!long;
|
sdch.offset = row["offset"].as!long;
|
||||||
sdch.size = row["size"].to!long;
|
sdch.size = row["size"].as!long;
|
||||||
sdch.content = cast(ubyte[]) row["content"].dup;
|
|
||||||
sdch.zstd = cast(bool) row["zstd"].to!int;
|
// content может быть NULL
|
||||||
sdch.zSize = row["z_size"].to!long;
|
auto contentBlob = cast(ubyte[]) row["content"].as!Blob(Blob.init);
|
||||||
sdch.sha256 = cast(ubyte[]) row["sha256"].dup;
|
sdch.content = contentBlob.length ? contentBlob.dup : null;
|
||||||
sdch.zSha256 = cast(ubyte[]) row["z_sha256"].dup;
|
|
||||||
|
sdch.zstd = row["zstd"].as!int != 0;
|
||||||
|
sdch.zSize = row["z_size"].as!long;
|
||||||
|
|
||||||
|
auto sha = cast(ubyte[]) row["sha256"].as!Blob(Blob.init);
|
||||||
|
if (sha.length) sdch.sha256[] = sha;
|
||||||
|
|
||||||
|
auto zsha = cast(ubyte[]) row["z_sha256"].as!Blob(Blob.init);
|
||||||
|
if (zsha.length) sdch.zSha256[] = zsha;
|
||||||
|
|
||||||
sdchs ~= sdch;
|
sdchs ~= sdch;
|
||||||
}
|
}
|
||||||
|
|
@ -657,28 +677,28 @@ public:
|
||||||
{
|
{
|
||||||
DBSnapshot snapshot;
|
DBSnapshot snapshot;
|
||||||
|
|
||||||
snapshot.id = cast(ubyte[]) row["id"].dup;
|
snapshot.id = row["id"].as!Blob(Blob.init);
|
||||||
snapshot.file = DBFile(
|
snapshot.file = DBFile(
|
||||||
Identifier(cast(ubyte[]) row["file_id"].dup),
|
Identifier(row["file_id"].as!Blob(Blob.init)),
|
||||||
row["file_name"].to!string
|
row["file_name"].as!string
|
||||||
);
|
);
|
||||||
snapshot.sha256 = cast(ubyte[]) row["sha256"].dup;
|
snapshot.sha256 = row["sha256"].as!Blob(Blob.init);
|
||||||
snapshot.description = row["description"].to!string;
|
snapshot.description = row["description"].as!string(""); // может быть NULL
|
||||||
snapshot.createdUtc = row["created_utc"].to!long;
|
snapshot.createdUtc = row["created_utc"].as!long;
|
||||||
snapshot.sourceLength = row["source_length"].to!long;
|
snapshot.sourceLength = row["source_length"].as!long;
|
||||||
snapshot.algoMin = row["algo_min"].to!long;
|
snapshot.algoMin = row["algo_min"].as!long;
|
||||||
snapshot.algoNormal = row["algo_normal"].to!long;
|
snapshot.algoNormal = row["algo_normal"].as!long;
|
||||||
snapshot.algoMax = row["algo_max"].to!long;
|
snapshot.algoMax = row["algo_max"].as!long;
|
||||||
snapshot.maskS = row["mask_s"].to!long;
|
snapshot.maskS = row["mask_s"].as!long;
|
||||||
snapshot.maskL = row["mask_l"].to!long;
|
snapshot.maskL = row["mask_l"].as!long;
|
||||||
snapshot.status = cast(SnapshotStatus) row["status"].to!int;
|
snapshot.status = cast(SnapshotStatus) row["status"].as!int;
|
||||||
snapshot.uid = row["uid"].to!long;
|
snapshot.uid = row["uid"].as!long;
|
||||||
snapshot.ruid = row["ruid"].to!long;
|
snapshot.ruid = row["ruid"].as!long;
|
||||||
snapshot.uidName = row["uid_name"].to!string;
|
snapshot.uidName = row["uid_name"].as!string;
|
||||||
snapshot.ruidName = row["ruid_name"].to!string;
|
snapshot.ruidName = row["ruid_name"].as!string;
|
||||||
snapshot.process = DBProcess(
|
snapshot.process = DBProcess(
|
||||||
Identifier(cast(ubyte[]) row["process_id"].dup),
|
Identifier(row["process_id"].as!Blob(Blob.init)),
|
||||||
row["process_name"].to!string
|
row["process_name"].as!string
|
||||||
);
|
);
|
||||||
|
|
||||||
snapshots ~= snapshot;
|
snapshots ~= snapshot;
|
||||||
|
|
@ -727,30 +747,29 @@ public:
|
||||||
{
|
{
|
||||||
DBSnapshot snapshot;
|
DBSnapshot snapshot;
|
||||||
|
|
||||||
snapshot.id = cast(ubyte[]) row["id"].dup;
|
snapshot.id = row["id"].as!Blob(Blob.init);
|
||||||
snapshot.file = DBFile(
|
snapshot.file = DBFile(
|
||||||
Identifier(cast(ubyte[]) row["file_id"].dup),
|
Identifier(row["file_id"].as!Blob(Blob.init)),
|
||||||
row["file_name"].to!string
|
row["file_name"].as!string
|
||||||
);
|
);
|
||||||
snapshot.sha256 = cast(ubyte[]) row["sha256"].dup;
|
snapshot.sha256 = row["sha256"].as!Blob(Blob.init);
|
||||||
snapshot.description = row["description"].to!string;
|
snapshot.description = row["description"].as!string("");
|
||||||
snapshot.createdUtc = row["created_utc"].to!long;
|
snapshot.createdUtc = row["created_utc"].as!long;
|
||||||
snapshot.sourceLength = row["source_length"].to!long;
|
snapshot.sourceLength = row["source_length"].as!long;
|
||||||
snapshot.algoMin = row["algo_min"].to!long;
|
snapshot.algoMin = row["algo_min"].as!long;
|
||||||
snapshot.algoNormal = row["algo_normal"].to!long;
|
snapshot.algoNormal = row["algo_normal"].as!long;
|
||||||
snapshot.algoMax = row["algo_max"].to!long;
|
snapshot.algoMax = row["algo_max"].as!long;
|
||||||
snapshot.maskS = row["mask_s"].to!long;
|
snapshot.maskS = row["mask_s"].as!long;
|
||||||
snapshot.maskL = row["mask_l"].to!long;
|
snapshot.maskL = row["mask_l"].as!long;
|
||||||
snapshot.status = cast(SnapshotStatus) row["status"].to!int;
|
snapshot.status = cast(SnapshotStatus) row["status"].as!int;
|
||||||
snapshot.uid = row["uid"].to!long;
|
snapshot.uid = row["uid"].as!long;
|
||||||
snapshot.ruid = row["ruid"].to!long;
|
snapshot.ruid = row["ruid"].as!long;
|
||||||
snapshot.uidName = row["uid_name"].to!string;
|
snapshot.uidName = row["uid_name"].as!string;
|
||||||
snapshot.ruidName = row["ruid_name"].to!string;
|
snapshot.ruidName = row["ruid_name"].as!string;
|
||||||
snapshot.process = DBProcess(
|
snapshot.process = DBProcess(
|
||||||
Identifier(cast(ubyte[]) row["process_id"].dup),
|
Identifier(row["process_id"].as!Blob(Blob.init)),
|
||||||
row["process_name"].to!string
|
row["process_name"].as!string
|
||||||
);
|
);
|
||||||
|
|
||||||
snapshots ~= snapshot;
|
snapshots ~= snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -793,31 +812,31 @@ public:
|
||||||
|
|
||||||
DBSnapshot snapshot;
|
DBSnapshot snapshot;
|
||||||
|
|
||||||
if (!queryResult.empty()) {
|
if (!queryResult.empty) {
|
||||||
auto data = queryResult.front();
|
auto data = queryResult.front;
|
||||||
|
|
||||||
snapshot.id = cast(ubyte[]) data["id"].dup;
|
snapshot.id = data["id"].as!Blob(Blob.init);
|
||||||
snapshot.file = DBFile(
|
snapshot.file = DBFile(
|
||||||
Identifier(cast(ubyte[]) data["file_id"].dup),
|
Identifier(data["file_id"].as!Blob(Blob.init)),
|
||||||
data["file_name"].to!string
|
data["file_name"].as!string
|
||||||
);
|
);
|
||||||
snapshot.sha256 = cast(ubyte[]) data["sha256"].dup;
|
snapshot.sha256 = data["sha256"].as!Blob(Blob.init);
|
||||||
snapshot.description = data["description"].to!string;
|
snapshot.description = data["description"].as!string("");
|
||||||
snapshot.createdUtc = data["created_utc"].to!long;
|
snapshot.createdUtc = data["created_utc"].as!long;
|
||||||
snapshot.sourceLength = data["source_length"].to!long;
|
snapshot.sourceLength = data["source_length"].as!long;
|
||||||
snapshot.algoMin = data["algo_min"].to!long;
|
snapshot.algoMin = data["algo_min"].as!long;
|
||||||
snapshot.algoNormal = data["algo_normal"].to!long;
|
snapshot.algoNormal = data["algo_normal"].as!long;
|
||||||
snapshot.algoMax = data["algo_max"].to!long;
|
snapshot.algoMax = data["algo_max"].as!long;
|
||||||
snapshot.maskS = data["mask_s"].to!long;
|
snapshot.maskS = data["mask_s"].as!long;
|
||||||
snapshot.maskL = data["mask_l"].to!long;
|
snapshot.maskL = data["mask_l"].as!long;
|
||||||
snapshot.status = cast(SnapshotStatus) data["status"].to!int;
|
snapshot.status = cast(SnapshotStatus) data["status"].as!int;
|
||||||
snapshot.uid = data["uid"].to!long;
|
snapshot.uid = data["uid"].as!long;
|
||||||
snapshot.ruid = data["ruid"].to!long;
|
snapshot.ruid = data["ruid"].as!long;
|
||||||
snapshot.uidName = data["uid_name"].to!string;
|
snapshot.uidName = data["uid_name"].as!string;
|
||||||
snapshot.ruidName = data["ruid_name"].to!string;
|
snapshot.ruidName = data["ruid_name"].as!string;
|
||||||
snapshot.process = DBProcess(
|
snapshot.process = DBProcess(
|
||||||
Identifier(cast(ubyte[]) data["process_id"].dup),
|
Identifier(data["process_id"].as!Blob(Blob.init)),
|
||||||
data["process_name"].to!string
|
data["process_name"].as!string
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -870,28 +889,28 @@ public:
|
||||||
{
|
{
|
||||||
DBSnapshot snapshot;
|
DBSnapshot snapshot;
|
||||||
|
|
||||||
snapshot.id = cast(ubyte[]) row["id"].dup;
|
snapshot.id = row["id"].as!Blob(Blob.init);
|
||||||
snapshot.file = DBFile(
|
snapshot.file = DBFile(
|
||||||
Identifier(cast(ubyte[]) row["file_id"].dup),
|
Identifier(row["file_id"].as!Blob(Blob.init)),
|
||||||
row["file_name"].to!string
|
row["file_name"].as!string
|
||||||
);
|
);
|
||||||
snapshot.sha256 = cast(ubyte[]) row["sha256"].dup;
|
snapshot.sha256 = row["sha256"].as!Blob(Blob.init);
|
||||||
snapshot.description = row["description"].to!string;
|
snapshot.description = row["description"].as!string("");
|
||||||
snapshot.createdUtc = row["created_utc"].to!long;
|
snapshot.createdUtc = row["created_utc"].as!long;
|
||||||
snapshot.sourceLength = row["source_length"].to!long;
|
snapshot.sourceLength = row["source_length"].as!long;
|
||||||
snapshot.algoMin = row["algo_min"].to!long;
|
snapshot.algoMin = row["algo_min"].as!long;
|
||||||
snapshot.algoNormal = row["algo_normal"].to!long;
|
snapshot.algoNormal = row["algo_normal"].as!long;
|
||||||
snapshot.algoMax = row["algo_max"].to!long;
|
snapshot.algoMax = row["algo_max"].as!long;
|
||||||
snapshot.maskS = row["mask_s"].to!long;
|
snapshot.maskS = row["mask_s"].as!long;
|
||||||
snapshot.maskL = row["mask_l"].to!long;
|
snapshot.maskL = row["mask_l"].as!long;
|
||||||
snapshot.status = cast(SnapshotStatus) row["status"].to!int;
|
snapshot.status = cast(SnapshotStatus) row["status"].as!int;
|
||||||
snapshot.uid = row["uid"].to!long;
|
snapshot.uid = row["uid"].as!long;
|
||||||
snapshot.ruid = row["ruid"].to!long;
|
snapshot.ruid = row["ruid"].as!long;
|
||||||
snapshot.uidName = row["uid_name"].to!string;
|
snapshot.uidName = row["uid_name"].as!string;
|
||||||
snapshot.ruidName = row["ruid_name"].to!string;
|
snapshot.ruidName = row["ruid_name"].as!string;
|
||||||
snapshot.process = DBProcess(
|
snapshot.process = DBProcess(
|
||||||
Identifier(cast(ubyte[]) row["process_id"].dup),
|
Identifier(row["process_id"].as!Blob(Blob.init)),
|
||||||
row["process_name"].to!string
|
row["process_name"].as!string
|
||||||
);
|
);
|
||||||
|
|
||||||
snapshots ~= snapshot;
|
snapshots ~= snapshot;
|
||||||
|
|
@ -902,6 +921,6 @@ public:
|
||||||
|
|
||||||
bool deleteSnapshot(Identifier id) {
|
bool deleteSnapshot(Identifier id) {
|
||||||
auto queryResult = sql("DELETE FROM snapshots WHERE id = ? RETURNING id", id[]);
|
auto queryResult = sql("DELETE FROM snapshots WHERE id = ? RETURNING id", id[]);
|
||||||
return !queryResult.empty();
|
return !queryResult.empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,12 +60,24 @@ public:
|
||||||
_data = data;
|
_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this(immutable(ubyte[]) data)
|
||||||
|
{
|
||||||
|
assert(data.length <= 16);
|
||||||
|
_data = data.dup;
|
||||||
|
}
|
||||||
|
|
||||||
this(ref const ubyte[16] data)
|
this(ref const ubyte[16] data)
|
||||||
{
|
{
|
||||||
assert(data.length <= 16);
|
assert(data.length <= 16);
|
||||||
_data = data.dup;
|
_data = data.dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void opAssign(immutable(ubyte[]) data)
|
||||||
|
{
|
||||||
|
assert(data.length <= 16);
|
||||||
|
_data = data.dup;
|
||||||
|
}
|
||||||
|
|
||||||
void opAssign(ubyte[] data)
|
void opAssign(ubyte[] data)
|
||||||
{
|
{
|
||||||
assert(data.length <= 16);
|
assert(data.length <= 16);
|
||||||
|
|
|
||||||
14
test/app.d
14
test/app.d
|
|
@ -72,13 +72,13 @@ void main()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Удаление файла
|
// Удаление файла
|
||||||
if (storage.deleteFile("example_file"))
|
// if (storage.deleteFile("example_file"))
|
||||||
writeln("Файл example_file удален.");
|
// writeln("Файл example_file удален.");
|
||||||
|
|
||||||
// Проверка: снимки удалены
|
// // Проверка: снимки удалены
|
||||||
auto remaining = storage.getSnapshots("example_file");
|
// auto remaining = storage.getSnapshots("example_file");
|
||||||
assert(remaining.length == 0);
|
// assert(remaining.length == 0);
|
||||||
writeln("Все снимки удалены.");
|
// writeln("Все снимки удалены.");
|
||||||
|
|
||||||
writeln("Версия библиотеки: ", storage.getVersion());
|
// writeln("Версия библиотеки: ", storage.getVersion());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue