From 54004647673989e4e4bf60b00cdf85bb5e6a467b Mon Sep 17 00:00:00 2001 From: Stephen Shkardoon Date: Thu, 13 May 2021 20:05:52 +1200 Subject: [PATCH] Add UNIQUE index on VirtualRepo to prevent duplicates While the code currently verifies whether an entry exists in the VirtualRepo table before creating a new one, it is possible that bugs in the code (such as race conditions) could result in extraneous entries in the table. This change enforces the entries within the table be unique, preventing the existing of a duplicate entry even if other areas of the code have bugs. This change does not implement an appropriate migration for the case where a server already has duplicate entries in the VirtualRepo table that would cause the constraint to fail to be added. This is a partial fix for haiwen/seafile#2449. --- scripts/sql/mysql/seafile.sql | 3 ++- scripts/sql/sqlite/seafile.sql | 1 + scripts/upgrade/sql/8.1.0/mysql/seafile.sql | 1 + scripts/upgrade/sql/8.1.0/sqlite3/seafile.sql | 1 + server/repo-mgr.c | 9 +++++++-- 5 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 scripts/upgrade/sql/8.1.0/mysql/seafile.sql create mode 100644 scripts/upgrade/sql/8.1.0/sqlite3/seafile.sql diff --git a/scripts/sql/mysql/seafile.sql b/scripts/sql/mysql/seafile.sql index ca4b5184..a136cf32 100644 --- a/scripts/sql/mysql/seafile.sql +++ b/scripts/sql/mysql/seafile.sql @@ -306,7 +306,8 @@ CREATE TABLE IF NOT EXISTS VirtualRepo ( path TEXT, base_commit CHAR(40), UNIQUE INDEX(repo_id), - INDEX(origin_repo) + INDEX(origin_repo), + UNIQUE INDEX(origin_repo,path) ) ENGINE=INNODB; CREATE TABLE IF NOT EXISTS WebAP ( diff --git a/scripts/sql/sqlite/seafile.sql b/scripts/sql/sqlite/seafile.sql index de9e40d6..e71d1f69 100644 --- a/scripts/sql/sqlite/seafile.sql +++ b/scripts/sql/sqlite/seafile.sql @@ -31,6 +31,7 @@ CREATE TABLE IF NOT EXISTS RepoValidSince (repo_id CHAR(37) PRIMARY KEY, timesta CREATE TABLE IF NOT EXISTS WebAP (repo_id CHAR(37) PRIMARY KEY, access_property CHAR(10)); CREATE TABLE IF NOT EXISTS VirtualRepo (repo_id CHAR(36) PRIMARY KEY, origin_repo CHAR(36), path TEXT, base_commit CHAR(40)); CREATE INDEX IF NOT EXISTS virtualrepo_origin_repo_idx ON VirtualRepo (origin_repo); +CREATE INDEX IF NOT EXISTS virtualrepo_unique_idx ON VirtualRepo (origin_repo, path); CREATE TABLE IF NOT EXISTS GarbageRepos (repo_id CHAR(36) PRIMARY KEY); CREATE TABLE IF NOT EXISTS RepoTrash (repo_id CHAR(36) PRIMARY KEY, repo_name VARCHAR(255), head_id CHAR(40), owner_id VARCHAR(255), size BIGINT UNSIGNED, org_id INTEGER, del_time BIGINT); CREATE INDEX IF NOT EXISTS repotrash_owner_id_idx ON RepoTrash(owner_id); diff --git a/scripts/upgrade/sql/8.1.0/mysql/seafile.sql b/scripts/upgrade/sql/8.1.0/mysql/seafile.sql new file mode 100644 index 00000000..e0c9e6ce --- /dev/null +++ b/scripts/upgrade/sql/8.1.0/mysql/seafile.sql @@ -0,0 +1 @@ +ALTER TABLE VirtualRepo ADD UNIQUE INDEX(origin_repo,path); diff --git a/scripts/upgrade/sql/8.1.0/sqlite3/seafile.sql b/scripts/upgrade/sql/8.1.0/sqlite3/seafile.sql new file mode 100644 index 00000000..8f3158ef --- /dev/null +++ b/scripts/upgrade/sql/8.1.0/sqlite3/seafile.sql @@ -0,0 +1 @@ +CREATE INDEX IF NOT EXISTS "virtualrepo_unique_idx" ON "VirtualRepo" ("origin_repo", "path"); diff --git a/server/repo-mgr.c b/server/repo-mgr.c index bbbf5256..a1046288 100644 --- a/server/repo-mgr.c +++ b/server/repo-mgr.c @@ -1039,8 +1039,8 @@ create_tables_mysql (SeafRepoManager *mgr) sql = "CREATE TABLE IF NOT EXISTS VirtualRepo (id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, " "repo_id CHAR(36)," - "origin_repo CHAR(36), path TEXT, base_commit CHAR(40), UNIQUE INDEX(repo_id), INDEX(origin_repo))" - "ENGINE=INNODB"; + "origin_repo CHAR(36), path TEXT, base_commit CHAR(40), UNIQUE INDEX(repo_id), INDEX(origin_repo)), " + "UNIQUE INDEX(origin_repo,path) ENGINE=INNODB"; if (seaf_db_query (db, sql) < 0) return -1; @@ -1195,6 +1195,11 @@ create_tables_sqlite (SeafRepoManager *mgr) if (seaf_db_query (db, sql) < 0) return -1; + sql = "CREATE INDEX IF NOT EXISTS virtualrepo_unique_idx " + "ON VirtualRepo (origin_repo, path)"; + if (seaf_db_query (db, sql) < 0) + return -1; + sql = "CREATE TABLE IF NOT EXISTS GarbageRepos (repo_id CHAR(36) PRIMARY KEY)"; if (seaf_db_query (db, sql) < 0) return -1;