Оптимизирована схема БД
This commit is contained in:
		
							parent
							
								
									541d09b8f4
								
							
						
					
					
						commit
						d62524e185
					
				
					 5 changed files with 61 additions and 115 deletions
				
			
		| 
						 | 
					@ -37,7 +37,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Параметры для CDC вынести в отдельные настройки (продумать)
 | 
							// Параметры для CDC вынести в отдельные настройки (продумать)
 | 
				
			||||||
		auto cdc = new CDC(300, 700, 1000, 0xFF, 0x0F);
 | 
							auto cdc = new CDC(256, 512, 1024, 0xFF, 0x0F);
 | 
				
			||||||
		// Разбить на фрагменты
 | 
							// Разбить на фрагменты
 | 
				
			||||||
		auto chunks = cdc.split(data);
 | 
							auto chunks = cdc.split(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,7 +81,6 @@ public:
 | 
				
			||||||
			snapshotChunk.snapshotId = idSnapshot;
 | 
								snapshotChunk.snapshotId = idSnapshot;
 | 
				
			||||||
			snapshotChunk.chunkIndex = chunk.index;
 | 
								snapshotChunk.chunkIndex = chunk.index;
 | 
				
			||||||
			snapshotChunk.offset = chunk.offset;
 | 
								snapshotChunk.offset = chunk.offset;
 | 
				
			||||||
			snapshotChunk.size = chunk.size;
 | 
					 | 
				
			||||||
			snapshotChunk.sha256 = chunk.sha256;
 | 
								snapshotChunk.sha256 = chunk.sha256;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_db.addSnapshotChunk(snapshotChunk);
 | 
								_db.addSnapshotChunk(snapshotChunk);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,13 +115,12 @@ public:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		sql(
 | 
							sql(
 | 
				
			||||||
			q{
 | 
								q{
 | 
				
			||||||
				INSERT INTO snapshot_chunks (snapshot_id, chunk_index, offset, size, sha256)
 | 
									INSERT INTO snapshot_chunks (snapshot_id, chunk_index, offset, sha256)
 | 
				
			||||||
				VALUES(?,?,?,?,?)
 | 
									VALUES(?,?,?,?)
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			snapshotChunk.snapshotId,
 | 
								snapshotChunk.snapshotId,
 | 
				
			||||||
			snapshotChunk.chunkIndex,
 | 
								snapshotChunk.chunkIndex,
 | 
				
			||||||
			snapshotChunk.offset,
 | 
								snapshotChunk.offset,
 | 
				
			||||||
			snapshotChunk.size,
 | 
					 | 
				
			||||||
			snapshotChunk.sha256[]
 | 
								snapshotChunk.sha256[]
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -225,8 +224,8 @@ public:
 | 
				
			||||||
	SnapshotDataChunk[] getChunks(long snapshotId) {
 | 
						SnapshotDataChunk[] getChunks(long snapshotId) {
 | 
				
			||||||
		auto queryResult = sql(
 | 
							auto queryResult = sql(
 | 
				
			||||||
			q{
 | 
								q{
 | 
				
			||||||
				SELECT sc.chunk_index, sc.offset, sc.size,
 | 
									SELECT sc.chunk_index, sc.offset,
 | 
				
			||||||
					b.content, b.zstd, b.z_size, b.sha256, b.z_sha256
 | 
										b.size, b.content, b.zstd, b.z_size, b.sha256, b.z_sha256
 | 
				
			||||||
				FROM snapshot_chunks sc
 | 
									FROM snapshot_chunks sc
 | 
				
			||||||
				JOIN blobs b ON b.sha256 = sc.sha256
 | 
									JOIN blobs b ON b.sha256 = sc.sha256
 | 
				
			||||||
				WHERE sc.snapshot_id = ?
 | 
									WHERE sc.snapshot_id = ?
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,124 +1,86 @@
 | 
				
			||||||
auto _scheme = [
 | 
					auto _scheme = [
 | 
				
			||||||
	q{
 | 
						q{
 | 
				
			||||||
		-- ------------------------------------------------------------
 | 
							-- ------------------------------------------------------------
 | 
				
			||||||
		-- Метаданные снимка
 | 
							-- Таблица snapshots
 | 
				
			||||||
		-- ------------------------------------------------------------
 | 
							-- ------------------------------------------------------------
 | 
				
			||||||
		CREATE TABLE IF NOT EXISTS snapshots (
 | 
							CREATE TABLE IF NOT EXISTS snapshots (
 | 
				
			||||||
			-- Уникальный числовой идентификатор снимка. Используется во внешних ключах.
 | 
								-- идентификатор снимка
 | 
				
			||||||
			id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
								id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
				
			||||||
 | 
								-- путь к исходному файлу
 | 
				
			||||||
			-- Путь к исходному файлу, для удобства навигации/поиска.
 | 
					 | 
				
			||||||
			file_path TEXT,
 | 
								file_path TEXT,
 | 
				
			||||||
 | 
								-- SHA-256 всего файла (BLOB(32))
 | 
				
			||||||
			file_sha256 BLOB NOT NULL CHECK (length(file_sha256) = 32),
 | 
								file_sha256 BLOB NOT NULL CHECK (length(file_sha256) = 32),
 | 
				
			||||||
 | 
								-- метка/название снимка
 | 
				
			||||||
			-- Произвольная метка/название снимка (для человека).
 | 
					 | 
				
			||||||
			label TEXT,
 | 
								label TEXT,
 | 
				
			||||||
 | 
								-- время создания (UTC)
 | 
				
			||||||
			-- Время создания записи (UTC). По умолчанию - текущее.
 | 
					 | 
				
			||||||
			created_utc TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP),
 | 
								created_utc TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP),
 | 
				
			||||||
 | 
								-- длина исходного файла в байтах
 | 
				
			||||||
			-- Полная длина исходного файла в байтах (до разбиения на чанки).
 | 
					 | 
				
			||||||
			source_length INTEGER NOT NULL,
 | 
								source_length INTEGER NOT NULL,
 | 
				
			||||||
 | 
								-- FastCDC: минимальный размер чанка
 | 
				
			||||||
			-- Пороговые размеры FastCDC: минимальный/целевой/максимальный размер чанка (в байтах).
 | 
					 | 
				
			||||||
			-- Фиксируются для воспроизводимости и сравнения результатов.
 | 
					 | 
				
			||||||
			algo_min INTEGER NOT NULL,
 | 
								algo_min INTEGER NOT NULL,
 | 
				
			||||||
 | 
								-- FastCDC: целевой размер чанка
 | 
				
			||||||
			algo_normal INTEGER NOT NULL,
 | 
								algo_normal INTEGER NOT NULL,
 | 
				
			||||||
 | 
								-- FastCDC: максимальный размер чанка
 | 
				
			||||||
			algo_max INTEGER NOT NULL,
 | 
								algo_max INTEGER NOT NULL,
 | 
				
			||||||
 | 
								-- FastCDC: маска S
 | 
				
			||||||
			-- Маски FastCDC для определения границ чанков (обычно вида 2^n - 1).
 | 
					 | 
				
			||||||
			-- Хранятся для воспроизводимости.
 | 
					 | 
				
			||||||
			mask_s INTEGER NOT NULL,
 | 
								mask_s INTEGER NOT NULL,
 | 
				
			||||||
 | 
								-- FastCDC: маска L
 | 
				
			||||||
			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 (typeof(status) = "integer" AND status IN (0,1))
 | 
									CHECK (status IN (0,1))
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	q{
 | 
						q{
 | 
				
			||||||
		-- ------------------------------------------------------------
 | 
							-- ------------------------------------------------------------
 | 
				
			||||||
		-- Уникальные куски содержимого (дедупликация по sha256)
 | 
							-- Таблица blobs
 | 
				
			||||||
		-- ------------------------------------------------------------
 | 
							-- ------------------------------------------------------------
 | 
				
			||||||
		CREATE TABLE IF NOT EXISTS blobs (
 | 
							CREATE TABLE IF NOT EXISTS blobs (
 | 
				
			||||||
			-- Хэш содержимого чанка. Храним как BLOB(32) (сырые 32 байта SHA-256).
 | 
								-- SHA-256 исходного содержимого (BLOB(32))
 | 
				
			||||||
			sha256 BLOB PRIMARY KEY CHECK (length(sha256) = 32),
 | 
								sha256 BLOB PRIMARY KEY CHECK (length(sha256) = 32),
 | 
				
			||||||
 | 
								-- SHA-256 сжатого содержимого (BLOB(32)) или NULL
 | 
				
			||||||
			-- Хэш сжатого содержимого (если zstd=1). Может быть NULL при zstd=0.
 | 
					 | 
				
			||||||
			z_sha256 BLOB,
 | 
								z_sha256 BLOB,
 | 
				
			||||||
 | 
								-- размер исходного содержимого, байт
 | 
				
			||||||
			-- Размер чанка в байтах (до сжатия).
 | 
					 | 
				
			||||||
			size INTEGER NOT NULL,
 | 
								size INTEGER NOT NULL,
 | 
				
			||||||
 | 
								-- размер сжатого содержимого, байт
 | 
				
			||||||
			-- Размер сжатого чанка (в байтах). Можно держать NOT NULL и заполнять =size при zstd=0,
 | 
								z_size INTEGER NOT NULL,
 | 
				
			||||||
			-- либо сделать NULL при zstd=0 (см. CHECK ниже допускает NULL).
 | 
								-- байты (сжатые при zstd=1, иначе исходные)
 | 
				
			||||||
			z_size INTEGER,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			-- Сырые байты: при zstd=1 здесь лежит сжатый блок, иначе - исходные байты.
 | 
					 | 
				
			||||||
			content BLOB NOT NULL,
 | 
								content BLOB NOT NULL,
 | 
				
			||||||
 | 
								-- время создания записи (UTC)
 | 
				
			||||||
			-- Таймштампы
 | 
					 | 
				
			||||||
			created_utc   TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP),
 | 
								created_utc   TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP),
 | 
				
			||||||
 | 
								-- время последней ссылки (UTC)
 | 
				
			||||||
			last_seen_utc TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP),
 | 
								last_seen_utc TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP),
 | 
				
			||||||
 | 
								-- число ссылок из snapshot_chunks
 | 
				
			||||||
			-- Счётчик ссылок из snapshot_chunks
 | 
					 | 
				
			||||||
			refcount INTEGER NOT NULL DEFAULT 0,
 | 
								refcount INTEGER NOT NULL DEFAULT 0,
 | 
				
			||||||
 | 
								-- 0=нет сжатия, 1=zstd
 | 
				
			||||||
			-- Флаг сжатия: 0 - без сжатия; 1 - zstd
 | 
					 | 
				
			||||||
			zstd INTEGER NOT NULL DEFAULT 0
 | 
								zstd INTEGER NOT NULL DEFAULT 0
 | 
				
			||||||
				CHECK (typeof(zstd) = "integer" AND zstd IN (0,1)),
 | 
									CHECK (zstd IN (0,1)),
 | 
				
			||||||
 | 
					 | 
				
			||||||
			-- Дополнительные гарантии целостности:
 | 
					 | 
				
			||||||
			CHECK (refcount >= 0),
 | 
								CHECK (refcount >= 0),
 | 
				
			||||||
 | 
					 | 
				
			||||||
			-- Если zstd=1, длина content должна равняться z_size;
 | 
					 | 
				
			||||||
			-- если zstd=0 - длина content должна равняться size.
 | 
					 | 
				
			||||||
			CHECK (
 | 
								CHECK (
 | 
				
			||||||
				(zstd = 1 AND z_size IS NOT NULL AND length(content) = z_size)
 | 
									(zstd = 1 AND length(content) = z_size) OR
 | 
				
			||||||
			OR (zstd = 0 AND length(content) = size )
 | 
									(zstd = 0 AND length(content) = size)
 | 
				
			||||||
			),
 | 
								),
 | 
				
			||||||
 | 
					 | 
				
			||||||
			-- Согласованность z_sha256 (если задан)
 | 
					 | 
				
			||||||
			CHECK (z_sha256 IS NULL OR length(z_sha256) = 32)
 | 
								CHECK (z_sha256 IS NULL OR length(z_sha256) = 32)
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	q{
 | 
						q{
 | 
				
			||||||
		-- ------------------------------------------------------------
 | 
							-- ------------------------------------------------------------
 | 
				
			||||||
		-- Состав снимка (упорядоченный список чанков)
 | 
							-- Таблица snapshot_chunks
 | 
				
			||||||
		-- ------------------------------------------------------------
 | 
							-- ------------------------------------------------------------
 | 
				
			||||||
		CREATE TABLE IF NOT EXISTS snapshot_chunks (
 | 
							CREATE TABLE IF NOT EXISTS snapshot_chunks (
 | 
				
			||||||
			-- Ссылка на snapshots.id. Определяет, к какому снимку относится строка.
 | 
								-- FK -> snapshots.id
 | 
				
			||||||
			snapshot_id INTEGER NOT NULL,
 | 
								snapshot_id INTEGER NOT NULL,
 | 
				
			||||||
 | 
								-- порядковый номер чанка в снимке
 | 
				
			||||||
			-- Позиция чанка в снимке (индексация на твой выбор - 0/1-based; важно быть последовательным).
 | 
					 | 
				
			||||||
			-- Обеспечивает порядок сборки.
 | 
					 | 
				
			||||||
			chunk_index INTEGER NOT NULL,
 | 
								chunk_index INTEGER NOT NULL,
 | 
				
			||||||
 | 
								-- смещение чанка в исходном файле, байт
 | 
				
			||||||
			-- Смещение чанка в исходном файле (в байтах).
 | 
					 | 
				
			||||||
			-- Можно восстановить суммой size предыдущих чанков, но хранение ускоряет проверки/отладку.
 | 
					 | 
				
			||||||
			offset INTEGER,
 | 
								offset INTEGER,
 | 
				
			||||||
 | 
								-- FK -> blobs.sha256 (BLOB(32))
 | 
				
			||||||
			-- Размер конкретного чанка в составе (дублирует blobs.size для ускорения/валидации).
 | 
					 | 
				
			||||||
			size INTEGER NOT NULL,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			-- Ссылка на blobs.sha256. Привязывает позицию к конкретному содержимому.
 | 
					 | 
				
			||||||
			-- Тип BLOB обязан совпадать с типом в родительской таблице.
 | 
					 | 
				
			||||||
			sha256 BLOB NOT NULL,
 | 
								sha256 BLOB NOT NULL,
 | 
				
			||||||
 | 
					 | 
				
			||||||
			-- Уникальность позиции чанка в рамках одного снимка.
 | 
					 | 
				
			||||||
			PRIMARY KEY (snapshot_id, chunk_index),
 | 
								PRIMARY KEY (snapshot_id, chunk_index),
 | 
				
			||||||
 | 
					 | 
				
			||||||
			-- Внешние ключи и их поведение:
 | 
					 | 
				
			||||||
			-- При удалении снимка его строки состава удаляются автоматически.
 | 
					 | 
				
			||||||
			FOREIGN KEY (snapshot_id)
 | 
								FOREIGN KEY (snapshot_id)
 | 
				
			||||||
				REFERENCES snapshots(id)
 | 
									REFERENCES snapshots(id)
 | 
				
			||||||
				ON UPDATE CASCADE
 | 
									ON UPDATE CASCADE
 | 
				
			||||||
				ON DELETE CASCADE,
 | 
									ON DELETE CASCADE,
 | 
				
			||||||
 | 
					 | 
				
			||||||
			-- Нельзя удалить blob, если он где-то используется; обновление ключа запрещено.
 | 
					 | 
				
			||||||
			FOREIGN KEY (sha256)
 | 
								FOREIGN KEY (sha256)
 | 
				
			||||||
				REFERENCES blobs(sha256)
 | 
									REFERENCES blobs(sha256)
 | 
				
			||||||
				ON UPDATE RESTRICT
 | 
									ON UPDATE RESTRICT
 | 
				
			||||||
| 
						 | 
					@ -126,27 +88,20 @@ auto _scheme = [
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	q{
 | 
						q{
 | 
				
			||||||
 | 
							-- Индекс для запросов вида: WHERE file_path=? AND file_sha256=?
 | 
				
			||||||
		CREATE INDEX IF NOT EXISTS idx_snapshots_path_sha
 | 
							CREATE INDEX IF NOT EXISTS idx_snapshots_path_sha
 | 
				
			||||||
			ON snapshots(file_path, file_sha256)
 | 
								ON snapshots(file_path, file_sha256)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	q{
 | 
						q{
 | 
				
			||||||
		-- Быстрый выбор всех чанков конкретного снимка (частый запрос).
 | 
							-- Индекс для обратного поиска использования blob по sha256
 | 
				
			||||||
		CREATE INDEX IF NOT EXISTS idx_snapshot_chunks_snapshot
 | 
					 | 
				
			||||||
			ON snapshot_chunks(snapshot_id)
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	q{
 | 
					 | 
				
			||||||
		-- Быстрый обратный поиск: где используется данный blob (для GC/аналитики).
 | 
					 | 
				
			||||||
		-- Индекс по BLOB(32) хорошо работает для точного поиска sha256.
 | 
					 | 
				
			||||||
		CREATE INDEX IF NOT EXISTS idx_snapshot_chunks_sha
 | 
							CREATE INDEX IF NOT EXISTS idx_snapshot_chunks_sha
 | 
				
			||||||
			ON snapshot_chunks(sha256)
 | 
								ON snapshot_chunks(sha256)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	// -- ------------------------------------------------------------
 | 
						// ------------------------------------------------------------
 | 
				
			||||||
	// -- Триггеры для управления refcount и GC blob'ов
 | 
						// Триггеры на поддержание refcount и статуса снимка
 | 
				
			||||||
	// -- ------------------------------------------------------------
 | 
						// ------------------------------------------------------------
 | 
				
			||||||
	q{
 | 
						q{
 | 
				
			||||||
		-- Инкремент счётчика при привязке чанка к снимку.
 | 
							-- AFTER INSERT: увеличить refcount и обновить last_seen_utc
 | 
				
			||||||
		-- Обновляем last_seen_utc, чтобы фиксировать "живость" контента.
 | 
					 | 
				
			||||||
		-- ВАЖНО: FK гарантирует, что соответствующий blobs.sha256 уже существует.
 | 
					 | 
				
			||||||
		CREATE TRIGGER IF NOT EXISTS trg_snapshot_chunks_ai
 | 
							CREATE TRIGGER IF NOT EXISTS trg_snapshot_chunks_ai
 | 
				
			||||||
		AFTER INSERT ON snapshot_chunks
 | 
							AFTER INSERT ON snapshot_chunks
 | 
				
			||||||
		BEGIN
 | 
							BEGIN
 | 
				
			||||||
| 
						 | 
					@ -157,8 +112,7 @@ auto _scheme = [
 | 
				
			||||||
		END
 | 
							END
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	q{
 | 
						q{
 | 
				
			||||||
		-- Декремент счётчика при удалении строки состава.
 | 
							-- AFTER DELETE: уменьшить refcount и удалить blob при refcount <= 0
 | 
				
			||||||
		-- Если счётчик стал 0 - удаляем неиспользуемый blob (авто-GC).
 | 
					 | 
				
			||||||
		CREATE TRIGGER IF NOT EXISTS trg_snapshot_chunks_ad
 | 
							CREATE TRIGGER IF NOT EXISTS trg_snapshot_chunks_ad
 | 
				
			||||||
		AFTER DELETE ON snapshot_chunks
 | 
							AFTER DELETE ON snapshot_chunks
 | 
				
			||||||
		BEGIN
 | 
							BEGIN
 | 
				
			||||||
| 
						 | 
					@ -172,9 +126,7 @@ auto _scheme = [
 | 
				
			||||||
		END
 | 
							END
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	q{
 | 
						q{
 | 
				
			||||||
		-- Корректировка счётчиков при смене sha256 в составе.
 | 
							-- AFTER UPDATE OF sha256: корректировка счётчиков при смене ссылки
 | 
				
			||||||
		-- Триггер срабатывает только при реальном изменении значения.
 | 
					 | 
				
			||||||
		-- Предполагается, что NEW.sha256 существует в blobs (иначе FK не даст обновить).
 | 
					 | 
				
			||||||
		CREATE TRIGGER IF NOT EXISTS trg_snapshot_chunks_au
 | 
							CREATE TRIGGER IF NOT EXISTS trg_snapshot_chunks_au
 | 
				
			||||||
		AFTER UPDATE OF sha256 ON snapshot_chunks
 | 
							AFTER UPDATE OF sha256 ON snapshot_chunks
 | 
				
			||||||
		FOR EACH ROW
 | 
							FOR EACH ROW
 | 
				
			||||||
| 
						 | 
					@ -195,31 +147,28 @@ auto _scheme = [
 | 
				
			||||||
		END
 | 
							END
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	q{
 | 
						q{
 | 
				
			||||||
		-- Автоматическая смена статуса снимка на 1 - "ready",
 | 
							-- AFTER INSERT: установить status=1 при совпадении суммы размеров с source_length
 | 
				
			||||||
		-- когда сумма размеров его чанков стала равна source_length.
 | 
					 | 
				
			||||||
		-- Примечание: простая эвристика; если потом удалишь/поменяешь чанки,
 | 
					 | 
				
			||||||
		-- триггер ниже вернёт статус обратно на 0 - "pending".
 | 
					 | 
				
			||||||
		CREATE TRIGGER IF NOT EXISTS trg_snapshots_mark_ready
 | 
							CREATE TRIGGER IF NOT EXISTS trg_snapshots_mark_ready
 | 
				
			||||||
		AFTER INSERT ON snapshot_chunks
 | 
							AFTER INSERT ON snapshot_chunks
 | 
				
			||||||
		BEGIN
 | 
							BEGIN
 | 
				
			||||||
		UPDATE snapshots
 | 
								UPDATE snapshots
 | 
				
			||||||
			SET status = 1
 | 
									SET status = 1
 | 
				
			||||||
		WHERE id = NEW.snapshot_id
 | 
								WHERE id = NEW.snapshot_id
 | 
				
			||||||
			AND (SELECT COALESCE(SUM(size),0)
 | 
									AND (SELECT COALESCE(SUM(b.size),0)
 | 
				
			||||||
					FROM snapshot_chunks
 | 
											FROM snapshot_chunks sc
 | 
				
			||||||
				WHERE snapshot_id = NEW.snapshot_id)
 | 
											JOIN blobs b ON b.sha256 = sc.sha256
 | 
				
			||||||
				= (SELECT source_length FROM snapshots WHERE id = NEW.snapshot_id);
 | 
											WHERE sc.snapshot_id = NEW.snapshot_id)
 | 
				
			||||||
 | 
										= (SELECT source_length FROM snapshots WHERE id = NEW.snapshot_id);
 | 
				
			||||||
		END
 | 
							END
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	q{
 | 
						q{
 | 
				
			||||||
		-- При удалении любого чанка снимок снова помечается как 0 - "pending".
 | 
							-- AFTER DELETE: установить status=0 для снимка, из которого удалён чанк
 | 
				
			||||||
		-- Это простой безопасный фоллбэк; следующая вставка приравняет суммы и вернёт 1 - "ready".
 | 
					 | 
				
			||||||
		CREATE TRIGGER IF NOT EXISTS trg_snapshots_mark_pending
 | 
							CREATE TRIGGER IF NOT EXISTS trg_snapshots_mark_pending
 | 
				
			||||||
		AFTER DELETE ON snapshot_chunks
 | 
							AFTER DELETE ON snapshot_chunks
 | 
				
			||||||
		BEGIN
 | 
							BEGIN
 | 
				
			||||||
		UPDATE snapshots
 | 
								UPDATE snapshots
 | 
				
			||||||
			SET status = 0
 | 
									SET status = 0
 | 
				
			||||||
		WHERE id = OLD.snapshot_id;
 | 
								WHERE id = OLD.snapshot_id;
 | 
				
			||||||
		END
 | 
							END
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,6 @@ struct SnapshotChunk
 | 
				
			||||||
	long snapshotId;
 | 
						long snapshotId;
 | 
				
			||||||
	long chunkIndex;
 | 
						long chunkIndex;
 | 
				
			||||||
	long offset;
 | 
						long offset;
 | 
				
			||||||
	long size;
 | 
					 | 
				
			||||||
	ubyte[32] sha256; // BLOB(32)
 | 
						ubyte[32] sha256; // BLOB(32)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,6 @@ import std.file : read;
 | 
				
			||||||
void main()
 | 
					void main()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto cas = new CAS("/tmp/base.db", true);
 | 
						auto cas = new CAS("/tmp/base.db", true);
 | 
				
			||||||
	// cas.saveSnapshot("/tmp/text", cast(ubyte[]) read("/tmp/text"));
 | 
						cas.saveSnapshot("/tmp/text", cast(ubyte[]) read("/tmp/text"));
 | 
				
			||||||
	cas.restoreSnapshot();
 | 
						// cas.restoreSnapshot();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue