Compare commits
No commits in common. "c9623f87e82fd575d29eeabd463de2f8ba1708ac" and "5bb4d65c9247d1c3382d5ef5ad64a1540c0ece9c" have entirely different histories.
c9623f87e8
...
5bb4d65c92
8 changed files with 30 additions and 124 deletions
|
|
@ -1,11 +1,5 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [0.1.1] - 2025-09-14
|
|
||||||
### Added
|
|
||||||
- Table `labels` for snapshot labels.
|
|
||||||
### Fixed
|
|
||||||
- Improved data integrity with label normalization.
|
|
||||||
|
|
||||||
## [0.1.0] — 2025-09-13
|
## [0.1.0] — 2025-09-13
|
||||||
### Added
|
### Added
|
||||||
- SQLite-backed snapshot library with content-defined chunking (FastCDC).
|
- SQLite-backed snapshot library with content-defined chunking (FastCDC).
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,6 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [0.1.1] - 2025-09-14
|
## [0.1.0] — 2025-09-13
|
||||||
### Added
|
|
||||||
- Таблица `labels` для меток снимков.
|
|
||||||
### Fixed
|
|
||||||
- Улучшена целостность данных при нормализации меток.
|
|
||||||
|
|
||||||
## [0.1.0] - 2025-09-13
|
|
||||||
### Added
|
### Added
|
||||||
- Библиотека для снимков данных на базе SQLite с контентно-зависимым разбиением (FastCDC).
|
- Библиотека для снимков данных на базе SQLite с контентно-зависимым разбиением (FastCDC).
|
||||||
- Дедупликация по SHA-256 чанков, опциональная компрессия Zstd.
|
- Дедупликация по SHA-256 чанков, опциональная компрессия Zstd.
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ chmod +x ./tools/gen.d
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cdcdb": "~>0.1"
|
"cdcdb": "~>0.1.0"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
* **Build**: `dub build`.
|
* **Build**: `dub build`.
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ chmod +x ./tools/gen.d
|
||||||
- **В `dub.json`**:
|
- **В `dub.json`**:
|
||||||
```json
|
```json
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cdcdb": "~>0.1"
|
"cdcdb": "~>0.1.0"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- **Сборка**: `dub build`.
|
- **Сборка**: `dub build`.
|
||||||
|
|
|
||||||
|
|
@ -176,14 +176,10 @@ public:
|
||||||
auto queryResult = sql(
|
auto queryResult = sql(
|
||||||
q{
|
q{
|
||||||
SELECT COALESCE(
|
SELECT COALESCE(
|
||||||
(
|
(SELECT (label = ? AND sha256 = ?)
|
||||||
SELECT (s.sha256 = ?2)
|
FROM snapshots
|
||||||
FROM snapshots s
|
ORDER BY created_utc DESC
|
||||||
JOIN labels l ON l.id = s.label
|
LIMIT 1),
|
||||||
WHERE l.name = ?1
|
|
||||||
ORDER BY s.created_utc DESC
|
|
||||||
LIMIT 1
|
|
||||||
),
|
|
||||||
0
|
0
|
||||||
) AS is_last;
|
) AS is_last;
|
||||||
}, label, sha256
|
}, label, sha256
|
||||||
|
|
@ -209,10 +205,7 @@ public:
|
||||||
mask_s,
|
mask_s,
|
||||||
mask_l,
|
mask_l,
|
||||||
status
|
status
|
||||||
)
|
) VALUES (?,?,?,?,?,?,?,?,?,?)
|
||||||
SELECT
|
|
||||||
(SELECT id FROM labels WHERE name = ?),
|
|
||||||
?,?,?,?,?,?,?,?,?
|
|
||||||
RETURNING id
|
RETURNING id
|
||||||
},
|
},
|
||||||
snapshot.label,
|
snapshot.label,
|
||||||
|
|
@ -254,18 +247,6 @@ public:
|
||||||
return !queryResult.empty();
|
return !queryResult.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool addLabel(string name)
|
|
||||||
{
|
|
||||||
auto queryResult = sql(
|
|
||||||
q{
|
|
||||||
INSERT INTO labels (name) VALUES (?)
|
|
||||||
ON CONFLICT(name) DO NOTHING
|
|
||||||
}, name
|
|
||||||
);
|
|
||||||
|
|
||||||
return !queryResult.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool addSnapshotChunk(DBSnapshotChunk snapshotChunk)
|
bool addSnapshotChunk(DBSnapshotChunk snapshotChunk)
|
||||||
{
|
{
|
||||||
auto queryResult = sql(
|
auto queryResult = sql(
|
||||||
|
|
@ -287,22 +268,9 @@ public:
|
||||||
{
|
{
|
||||||
auto queryResult = sql(
|
auto queryResult = sql(
|
||||||
q{
|
q{
|
||||||
SELECT
|
SELECT id, label, sha256, description, created_utc, source_length,
|
||||||
s.id,
|
algo_min, algo_normal, algo_max, mask_s, mask_l, status
|
||||||
l.name label,
|
FROM snapshots WHERE id = ?
|
||||||
s.sha256,
|
|
||||||
s.description,
|
|
||||||
s.created_utc,
|
|
||||||
s.source_length,
|
|
||||||
s.algo_min,
|
|
||||||
s.algo_normal,
|
|
||||||
s.algo_max,
|
|
||||||
s.mask_s,
|
|
||||||
s.mask_l,
|
|
||||||
s.status
|
|
||||||
FROM snapshots s
|
|
||||||
JOIN labels l ON l.id = s.label
|
|
||||||
WHERE s.id = ?
|
|
||||||
}, id
|
}, id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -333,22 +301,9 @@ public:
|
||||||
{
|
{
|
||||||
auto queryResult = sql(
|
auto queryResult = sql(
|
||||||
q{
|
q{
|
||||||
SELECT
|
SELECT id, label, sha256, description, created_utc, source_length,
|
||||||
s.id,
|
algo_min, algo_normal, algo_max, mask_s, mask_l, status
|
||||||
l.name label,
|
FROM snapshots WHERE (length(?) = 0 OR label = ?1);
|
||||||
s.sha256,
|
|
||||||
s.description,
|
|
||||||
s.created_utc,
|
|
||||||
s.source_length,
|
|
||||||
s.algo_min,
|
|
||||||
s.algo_normal,
|
|
||||||
s.algo_max,
|
|
||||||
s.mask_s,
|
|
||||||
s.mask_l,
|
|
||||||
s.status
|
|
||||||
FROM snapshots s
|
|
||||||
JOIN labels l ON l.id = s.label AND (length(?) = 0 OR l.name = ?1)
|
|
||||||
ORDER BY s.created_utc, s.id;
|
|
||||||
}, label
|
}, label
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -424,7 +379,7 @@ public:
|
||||||
auto queryResult = sql(
|
auto queryResult = sql(
|
||||||
q{
|
q{
|
||||||
DELETE FROM snapshots
|
DELETE FROM snapshots
|
||||||
WHERE label = (SELECT id FROM labels WHERE name = ?)
|
WHERE label = ?
|
||||||
RETURNING 1;
|
RETURNING 1;
|
||||||
}, label);
|
}, label);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,4 @@
|
||||||
auto _scheme = [
|
auto _scheme = [
|
||||||
q{
|
|
||||||
-- ------------------------------------------------------------
|
|
||||||
-- Таблица labels
|
|
||||||
-- ------------------------------------------------------------
|
|
||||||
CREATE TABLE IF NOT EXISTS labels (
|
|
||||||
-- идентификатор метки
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
-- имя метки
|
|
||||||
name TEXT NOT NULL UNIQUE
|
|
||||||
)
|
|
||||||
},
|
|
||||||
q{
|
|
||||||
-- Индекс по имени метки
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_labels_name
|
|
||||||
ON labels(name)
|
|
||||||
},
|
|
||||||
q{
|
q{
|
||||||
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
||||||
-- Таблица snapshots
|
-- Таблица snapshots
|
||||||
|
|
@ -23,7 +7,7 @@ auto _scheme = [
|
||||||
-- идентификатор снимка
|
-- идентификатор снимка
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
-- метка/название снимка
|
-- метка/название снимка
|
||||||
label INTEGER NOT NULL,
|
label TEXT NOT NULL,
|
||||||
-- SHA-256 всего файла (BLOB(32))
|
-- SHA-256 всего файла (BLOB(32))
|
||||||
sha256 BLOB NOT NULL CHECK (length(sha256) = 32),
|
sha256 BLOB NOT NULL CHECK (length(sha256) = 32),
|
||||||
-- Комментарий/описание
|
-- Комментарий/описание
|
||||||
|
|
@ -44,11 +28,7 @@ auto _scheme = [
|
||||||
mask_l INTEGER NOT NULL,
|
mask_l INTEGER NOT NULL,
|
||||||
-- 0=pending, 1=ready
|
-- 0=pending, 1=ready
|
||||||
status INTEGER NOT NULL DEFAULT 0
|
status INTEGER NOT NULL DEFAULT 0
|
||||||
CHECK (status IN (0,1)),
|
CHECK (status IN (0,1))
|
||||||
FOREIGN KEY (label)
|
|
||||||
REFERENCES labels(id)
|
|
||||||
ON UPDATE CASCADE
|
|
||||||
ON DELETE CASCADE
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
q{
|
q{
|
||||||
|
|
@ -269,20 +249,5 @@ auto _scheme = [
|
||||||
BEGIN
|
BEGIN
|
||||||
SELECT RAISE(ABORT, "blobs: разрешён UPDATE только полей last_seen_utc и refcount");
|
SELECT RAISE(ABORT, "blobs: разрешён UPDATE только полей last_seen_utc и refcount");
|
||||||
END
|
END
|
||||||
},
|
|
||||||
q{
|
|
||||||
-- ------------------------------------------------------------
|
|
||||||
-- Удаление записи из labels, если удалён последний snapshot
|
|
||||||
-- ------------------------------------------------------------
|
|
||||||
CREATE TRIGGER IF NOT EXISTS trg_snapshots_delete_label
|
|
||||||
AFTER DELETE ON snapshots
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
DELETE FROM labels
|
|
||||||
WHERE id = OLD.label
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM snapshots WHERE label = OLD.label
|
|
||||||
);
|
|
||||||
END;
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,18 @@ public:
|
||||||
if (_db.isLast(label, sha256))
|
if (_db.isLast(label, sha256))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
DBSnapshot dbSnapshot;
|
||||||
|
|
||||||
|
dbSnapshot.label = label;
|
||||||
|
dbSnapshot.sha256 = sha256;
|
||||||
|
dbSnapshot.description = description;
|
||||||
|
dbSnapshot.sourceLength = data.length;
|
||||||
|
dbSnapshot.algoMin = _minSize;
|
||||||
|
dbSnapshot.algoNormal = _normalSize;
|
||||||
|
dbSnapshot.algoMax = _maxSize;
|
||||||
|
dbSnapshot.maskS = _maskS;
|
||||||
|
dbSnapshot.maskL = _maskL;
|
||||||
|
|
||||||
_db.beginImmediate();
|
_db.beginImmediate();
|
||||||
|
|
||||||
bool ok;
|
bool ok;
|
||||||
|
|
@ -126,20 +138,6 @@ public:
|
||||||
_db.commit();
|
_db.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
_db.addLabel(label);
|
|
||||||
|
|
||||||
DBSnapshot dbSnapshot;
|
|
||||||
|
|
||||||
dbSnapshot.label = label;
|
|
||||||
dbSnapshot.sha256 = sha256;
|
|
||||||
dbSnapshot.description = description;
|
|
||||||
dbSnapshot.sourceLength = data.length;
|
|
||||||
dbSnapshot.algoMin = _minSize;
|
|
||||||
dbSnapshot.algoNormal = _normalSize;
|
|
||||||
dbSnapshot.algoMax = _maxSize;
|
|
||||||
dbSnapshot.maskS = _maskS;
|
|
||||||
dbSnapshot.maskL = _maskL;
|
|
||||||
|
|
||||||
auto idSnapshot = _db.addSnapshot(dbSnapshot);
|
auto idSnapshot = _db.addSnapshot(dbSnapshot);
|
||||||
|
|
||||||
DBSnapshotChunk dbSnapshotChunk;
|
DBSnapshotChunk dbSnapshotChunk;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
module cdcdb.version_;
|
module cdcdb.version_;
|
||||||
|
|
||||||
enum cdcdbVersion = "0.1.1";
|
enum cdcdbVersion = "0.1.0";
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue