Compare commits

..

No commits in common. "c9623f87e82fd575d29eeabd463de2f8ba1708ac" and "5bb4d65c9247d1c3382d5ef5ad64a1540c0ece9c" have entirely different histories.

8 changed files with 30 additions and 124 deletions

View file

@ -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).

View file

@ -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.

View file

@ -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`.

View file

@ -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`.

View file

@ -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);

View file

@ -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;
} }
]; ];

View file

@ -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;

View file

@ -1,3 +1,3 @@
module cdcdb.version_; module cdcdb.version_;
enum cdcdbVersion = "0.1.1"; enum cdcdbVersion = "0.1.0";