Track unfinished media destinations for channel cleanup
This commit is contained in:
1 parent
8cba8ef3e6
commit
b3a223521c
2 files changed
+48
-6
No files matched your search
@@ -124,6 +124,23 @@ int media_index_set_base(sqlite3* db, const char* base) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int media_index_track_preparation(sqlite3* db, const char* chat_id, const char* path, const char* base) {
|
||||
char location[MEDIA_PATH_MAX]; sqlite3_stmt* st = NULL;
|
||||
if (!db || !chat_id || !*chat_id || strlen(chat_id) >= 64 || media_index_location(path, base, location)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media_index invalid preparation path/channel"); return -1;
|
||||
}
|
||||
int rc = sqlite3_prepare_v2(db, "INSERT INTO media_preparations(chat_id,location) VALUES(?,?) ON CONFLICT DO NOTHING",
|
||||
-1, &st, NULL);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_text(st, 1, chat_id, -1, SQLITE_STATIC);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_text(st, 2, location, -1, SQLITE_STATIC);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_step(st);
|
||||
int finish = st ? sqlite3_finalize(st) : SQLITE_OK;
|
||||
if (rc == SQLITE_DONE && finish == SQLITE_OK) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "media_index preparation tracked chat=%s path=%s", chat_id, location); return 0;
|
||||
}
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media_index track preparation chat=%s rc=%d: %s", chat_id, rc, sqlite3_errmsg(db)); return -1;
|
||||
}
|
||||
|
||||
static int mi_insert(sqlite3* db,
|
||||
const uint8_t* media_id, const uint8_t* block_id,
|
||||
const uint8_t* content_hash,
|
||||
@@ -198,7 +215,9 @@ int media_index_init(sqlite3* db) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mi_exec(db, "CREATE UNIQUE INDEX IF NOT EXISTS idx_media_files_block_id ON media_files(block_id)")
|
||||
if (mi_exec(db, "CREATE TABLE IF NOT EXISTS media_preparations(chat_id TEXT NOT NULL,location TEXT NOT NULL,"
|
||||
"PRIMARY KEY(chat_id,location))")
|
||||
|| mi_exec(db, "CREATE UNIQUE INDEX IF NOT EXISTS idx_media_files_block_id ON media_files(block_id)")
|
||||
|| mi_exec(db, "CREATE INDEX IF NOT EXISTS idx_media_files_media_id ON media_files(media_id)")
|
||||
|| mi_exec(db, "CREATE INDEX IF NOT EXISTS idx_media_files_chat_id ON media_files(chat_id)")
|
||||
|| mi_exec(db, "CREATE INDEX IF NOT EXISTS idx_media_files_node_id ON media_files(node_id)")
|
||||
@@ -243,9 +262,9 @@ int media_index_delete_channel(sqlite3* db, const char* chat_id, const char* med
|
||||
struct mi_delete_file { char location[MEDIA_PATH_MAX]; char path[MEDIA_PATH_MAX]; int shared; };
|
||||
struct mi_delete_file* files = NULL; uint32_t count = 0;
|
||||
sqlite3_stmt* st = NULL;
|
||||
const char* query = "SELECT DISTINCT location,EXISTS(SELECT 1 FROM media_files other"
|
||||
" WHERE other.location=mine.location AND other.chat_id!=mine.chat_id)"
|
||||
" FROM media_files mine WHERE chat_id=?";
|
||||
const char* query = "WITH paths AS (SELECT chat_id,location FROM media_files UNION SELECT chat_id,location FROM media_preparations)"
|
||||
" SELECT location,EXISTS(SELECT 1 FROM paths other WHERE other.location=mine.location AND other.chat_id!=mine.chat_id)"
|
||||
" FROM paths mine WHERE chat_id=?";
|
||||
int rc = sqlite3_prepare_v2(db, query, -1, &st, NULL);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_text(st, 1, chat_id, -1, SQLITE_STATIC);
|
||||
if (rc != SQLITE_OK) goto failed;
|
||||
@@ -265,16 +284,23 @@ int media_index_delete_channel(sqlite3* db, const char* chat_id, const char* med
|
||||
if (rc != SQLITE_DONE) goto failed;
|
||||
rc = sqlite3_finalize(st); st = NULL;
|
||||
if (rc != SQLITE_OK) goto failed;
|
||||
rc = sqlite3_prepare_v2(db, "DELETE FROM media_files WHERE chat_id=? AND location=?", -1, &st, NULL);
|
||||
rc = sqlite3_prepare_v2(db, "DELETE FROM media_preparations WHERE chat_id=? AND location=?", -1, &st, NULL);
|
||||
if (rc != SQLITE_OK) goto failed;
|
||||
int errors = 0, rows = 0;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (!files[i].shared && mi_remove(files[i].path)) { errors++; continue; }
|
||||
sqlite3_stmt* blocks = NULL;
|
||||
rc = sqlite3_prepare_v2(db, "DELETE FROM media_files WHERE chat_id=? AND location=?", -1, &blocks, NULL);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_text(blocks, 1, chat_id, -1, SQLITE_STATIC);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_text(blocks, 2, files[i].location, -1, SQLITE_STATIC);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_step(blocks);
|
||||
int finish = blocks ? sqlite3_finalize(blocks) : SQLITE_OK;
|
||||
if (rc != SQLITE_DONE || finish != SQLITE_OK) goto failed;
|
||||
rows += sqlite3_changes(db);
|
||||
rc = sqlite3_bind_text(st, 1, chat_id, -1, SQLITE_STATIC);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_text(st, 2, files[i].location, -1, SQLITE_STATIC);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_step(st);
|
||||
if (rc != SQLITE_DONE) goto failed;
|
||||
rows += sqlite3_changes(db);
|
||||
rc = sqlite3_reset(st);
|
||||
if (rc != SQLITE_OK) goto failed;
|
||||
}
|
||||
@@ -346,6 +372,18 @@ static int mi_register_file(sqlite3* db, const struct media_index_result* result
|
||||
if (mi_insert(db, result->media_id, result->block_ids + (size_t)n * 16, result->content_hash,
|
||||
chat_id, location, node_id, signature, ts, result->file_size, size, n, offset)) { failed = 1; break; }
|
||||
}
|
||||
if (!failed) {
|
||||
sqlite3_stmt* st = NULL;
|
||||
int rc = sqlite3_prepare_v2(db, "DELETE FROM media_preparations WHERE chat_id=? AND location=?", -1, &st, NULL);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_text(st, 1, chat_id, -1, SQLITE_STATIC);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_text(st, 2, location, -1, SQLITE_STATIC);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_step(st);
|
||||
int finish = st ? sqlite3_finalize(st) : SQLITE_OK;
|
||||
if (rc != SQLITE_DONE || finish != SQLITE_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media_index clearing preparation failed chat=%s rc=%d: %s", chat_id, rc, sqlite3_errmsg(db));
|
||||
failed = 1;
|
||||
}
|
||||
}
|
||||
if (mi_end_registration(db, failed)) return -1;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "media_index registered chat=%s blocks=%d path=%s signed=%d",
|
||||
chat_id, result->num_blocks, location, key != NULL);
|
||||
@@ -505,6 +543,7 @@ void media_index_register_async(
|
||||
|| strlen(media_base) >= sizeof(((struct mi_reg_ctx*)0)->media_base)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media_index register oversized/empty path"); cb(cb_arg, -1, NULL); return;
|
||||
}
|
||||
if (media_index_track_preparation(db, chat_id, dest_path, media_base)) { cb(cb_arg, -1, NULL); return; }
|
||||
struct mi_reg_ctx* ctx = u_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media_index context allocation failed"); cb(cb_arg, -1, NULL); return; }
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ int media_index_path(const char* base, const char* location, char path[MEDIA_PAT
|
||||
* get возвращает проверенную базу; 0/-1. Смена базы при работающем ядре не поддерживается. */
|
||||
int media_index_set_base(sqlite3* db, const char* base);
|
||||
int media_index_get_base(sqlite3* db, char base[MEDIA_BASE_MAX]);
|
||||
/* Учесть назначение до файловой подготовки. Ошибка подготовки оставляет запись для delete_channel;
|
||||
* успешная регистрация файла удаляет её в той же транзакции. Сам файл здесь не меняется. 0/-1. */
|
||||
int media_index_track_preparation(sqlite3* db, const char* chat_id, const char* path, const char* base);
|
||||
|
||||
struct media_index_result {
|
||||
uint8_t media_id[16];
|
||||
|
||||
Reference in new issue
Block a user