1
0
mirror of https://github.com/haiwen/seafile-server.git synced 2025-09-25 14:42:52 +00:00

Merge branch '8.0'

This commit is contained in:
杨赫然
2021-02-05 15:40:48 +08:00
7 changed files with 372 additions and 26 deletions

View File

@@ -35,11 +35,12 @@ struct SeafDBRow {
struct SeafDBTrans {
DBConnection *conn;
gboolean need_close;
};
typedef struct DBOperations {
DBConnection* (*get_connection)(SeafDB *db);
void (*release_connection)(DBConnection *conn);
void (*release_connection)(DBConnection *conn, gboolean need_close);
int (*execute_sql_no_stmt)(DBConnection *conn, const char *sql);
int (*execute_sql)(DBConnection *conn, const char *sql,
int n, va_list args);
@@ -138,7 +139,7 @@ out:
}
static void
mysql_conn_pool_release_connection (DBConnection *conn)
mysql_conn_pool_release_connection (DBConnection *conn, gboolean need_close)
{
if (!conn)
return;
@@ -148,6 +149,14 @@ mysql_conn_pool_release_connection (DBConnection *conn)
return;
}
if (need_close) {
pthread_mutex_lock (&conn->pool->lock);
g_ptr_array_remove (conn->pool->connections, conn);
pthread_mutex_unlock (&conn->pool->lock);
mysql_db_release_connection (conn);
return;
}
pthread_mutex_lock (&conn->pool->lock);
conn->is_available = TRUE;
pthread_mutex_unlock (&conn->pool->lock);
@@ -227,7 +236,7 @@ sqlite_db_new (const char *db_path);
static DBConnection *
sqlite_db_get_connection (SeafDB *db);
static void
sqlite_db_release_connection (DBConnection *vconn);
sqlite_db_release_connection (DBConnection *vconn, gboolean need_close);
static int
sqlite_db_execute_sql_no_stmt (DBConnection *vconn, const char *sql);
static int
@@ -284,7 +293,7 @@ seaf_db_query (SeafDB *db, const char *sql)
int ret;
ret = db_ops.execute_sql_no_stmt (conn, sql);
db_ops.release_connection (conn);
db_ops.release_connection (conn, ret < 0);
return ret;
}
@@ -358,7 +367,7 @@ seaf_db_statement_query (SeafDB *db, const char *sql, int n, ...)
ret = db_ops.execute_sql (conn, sql, n, args);
va_end (args);
db_ops.release_connection (conn);
db_ops.release_connection (conn, ret < 0);
return ret;
}
@@ -380,7 +389,7 @@ seaf_db_statement_exists (SeafDB *db, const char *sql, gboolean *db_err, int n,
n_rows = db_ops.query_foreach_row (conn, sql, NULL, NULL, n, args);
va_end (args);
db_ops.release_connection(conn);
db_ops.release_connection(conn, n_rows < 0);
if (n_rows < 0) {
*db_err = TRUE;
@@ -408,7 +417,7 @@ seaf_db_statement_foreach_row (SeafDB *db, const char *sql,
ret = db_ops.query_foreach_row (conn, sql, callback, data, n, args);
va_end (args);
db_ops.release_connection (conn);
db_ops.release_connection (conn, ret < 0);
return ret;
}
@@ -439,7 +448,7 @@ seaf_db_statement_get_int (SeafDB *db, const char *sql, int n, ...)
rc = db_ops.query_foreach_row (conn, sql, get_int_cb, &ret, n, args);
va_end (args);
db_ops.release_connection (conn);
db_ops.release_connection (conn, rc < 0);
if (rc < 0)
return -1;
@@ -473,7 +482,7 @@ seaf_db_statement_get_int64 (SeafDB *db, const char *sql, int n, ...)
rc = db_ops.query_foreach_row (conn, sql, get_int64_cb, &ret, n, args);
va_end(args);
db_ops.release_connection (conn);
db_ops.release_connection (conn, rc < 0);
if (rc < 0)
return -1;
@@ -507,7 +516,7 @@ seaf_db_statement_get_string (SeafDB *db, const char *sql, int n, ...)
rc = db_ops.query_foreach_row (conn, sql, get_string_cb, &ret, n, args);
va_end(args);
db_ops.release_connection (conn);
db_ops.release_connection (conn, rc < 0);
if (rc < 0)
return NULL;
@@ -527,7 +536,7 @@ seaf_db_begin_transaction (SeafDB *db)
}
if (db_ops.execute_sql_no_stmt (conn, "BEGIN") < 0) {
db_ops.release_connection (conn);
db_ops.release_connection (conn, TRUE);
return trans;
}
@@ -540,7 +549,7 @@ seaf_db_begin_transaction (SeafDB *db)
void
seaf_db_trans_close (SeafDBTrans *trans)
{
db_ops.release_connection (trans->conn);
db_ops.release_connection (trans->conn, trans->need_close);
g_free (trans);
}
@@ -550,6 +559,7 @@ seaf_db_commit (SeafDBTrans *trans)
DBConnection *conn = trans->conn;
if (db_ops.execute_sql_no_stmt (conn, "COMMIT") < 0) {
trans->need_close = TRUE;
return -1;
}
@@ -562,6 +572,7 @@ seaf_db_rollback (SeafDBTrans *trans)
DBConnection *conn = trans->conn;
if (db_ops.execute_sql_no_stmt (conn, "ROLLBACK") < 0) {
trans->need_close = TRUE;
return -1;
}
@@ -578,6 +589,9 @@ seaf_db_trans_query (SeafDBTrans *trans, const char *sql, int n, ...)
ret = db_ops.execute_sql (trans->conn, sql, n, args);
va_end (args);
if (ret < 0)
trans->need_close = TRUE;
return ret;
}
@@ -595,6 +609,7 @@ seaf_db_trans_check_for_existence (SeafDBTrans *trans,
va_end (args);
if (n_rows < 0) {
trans->need_close = TRUE;
*db_err = TRUE;
return FALSE;
} else {
@@ -615,6 +630,9 @@ seaf_db_trans_foreach_selected_row (SeafDBTrans *trans, const char *sql,
ret = db_ops.query_foreach_row (trans->conn, sql, callback, data, n, args);
va_end (args);
if (ret < 0)
trans->need_close = TRUE;
return ret;
}
@@ -679,6 +697,8 @@ mysql_db_new (const char *host,
return (SeafDB *)db;
}
typedef char my_bool;
static DBConnection *
mysql_db_get_connection (SeafDB *vdb)
{
@@ -1200,7 +1220,7 @@ sqlite_db_get_connection (SeafDB *vdb)
}
static void
sqlite_db_release_connection (DBConnection *vconn)
sqlite_db_release_connection (DBConnection *vconn, gboolean need_close)
{
if (!vconn)
return;

View File

@@ -90,6 +90,7 @@ seafile_session_new(const char *central_config_dir,
session->ccnet_dir = abs_ccnet_dir;
session->tmp_file_dir = tmp_file_dir;
session->config = config;
session->ccnet_config = ccnet_config;
session->excluded_users = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);

View File

@@ -0,0 +1,4 @@
ALTER TABLE `VirusFile` ADD COLUMN IF NOT EXISTS `has_ignored` TINYINT(1) NOT NULL DEFAULT 0;
ALTER TABLE `VirusFile` CHANGE `has_handle` `has_deleted` TINYINT(1);
ALTER TABLE `VirusFile` ADD INDEX IF NOT EXISTS `has_deleted` (`has_deleted`);
ALTER TABLE `VirusFile` ADD INDEX IF NOT EXISTS `has_ignored` (`has_ignored`);

View File

@@ -38,7 +38,10 @@ CREATE TABLE IF NOT EXISTS `ocm_share_received` (
KEY `ocm_share_received_provider_id_60c873e0` (`provider_id`)
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `VirusFile` ADD COLUMN IF NOT EXISTS `has_ignored` TINYINT(1) NOT NULL DEFAULT 0;
ALTER TABLE `VirusFile` CHANGE `has_handle` `has_deleted` TINYINT(1);
ALTER TABLE `VirusFile` ADD INDEX IF NOT EXISTS `has_deleted` (`has_deleted`);
ALTER TABLE `VirusFile` ADD INDEX IF NOT EXISTS `has_ignored` (`has_ignored`);
CREATE TABLE IF NOT EXISTS `repo_auto_delete` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`repo_id` varchar(36) NOT NULL,
`days` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `repo_id` (`repo_id`)
) ENGINE = InnoDB DEFAULT CHARSET=utf8;

View File

@@ -0,0 +1,9 @@
DROP TABLE IF EXISTS "VirusFile_old";
ALTER TABLE "VirusFile" RENAME TO "VirusFile_old";
CREATE TABLE IF NOT EXISTS "VirusFile" ("vid" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "repo_id" varchar(36) NOT NULL, "commit_id" varchar(40) NOT NULL, "file_path" text NOT NULL, "has_deleted" tinyint(1) NOT NULL, "has_ignored" TINYINT(1) NOT NULL DEFAULT 0);
INSERT INTO "VirusFile" ("vid", "repo_id", "commit_id", "file_path", "has_deleted") SELECT "vid", "repo_id", "commit_id", "file_path", "has_handle" FROM "VirusFile_old";
DROP TABLE "VirusFile_old";
CREATE INDEX IF NOT EXISTS "VirusFile_repo_id_yewnci4gd" ON "VirusFile" ("repo_id");
CREATE INDEX IF NOT EXISTS "VirusFile_has_deleted_834ndyts" ON "VirusFile" ("has_deleted");
CREATE INDEX IF NOT EXISTS "VirusFile_has_ignored_d84tvuwg" ON "VirusFile" ("has_ignored");

View File

@@ -11,12 +11,4 @@ CREATE INDEX IF NOT EXISTS "ocm_share_received_from_server_url_10527b80" ON "ocm
CREATE INDEX IF NOT EXISTS "ocm_share_received_repo_id_9e77a1b9" ON "ocm_share_received" ("repo_id");
CREATE INDEX IF NOT EXISTS "ocm_share_received_provider_id_60c873e0" ON "ocm_share_received" ("provider_id");
DROP TABLE IF EXISTS "VirusFile_old";
ALTER TABLE "VirusFile" RENAME TO "VirusFile_old";
CREATE TABLE IF NOT EXISTS "VirusFile" ("vid" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "repo_id" varchar(36) NOT NULL, "commit_id" varchar(40) NOT NULL, "file_path" text NOT NULL, "has_deleted" tinyint(1) NOT NULL, "has_ignored" TINYINT(1) NOT NULL DEFAULT 0);
INSERT INTO "VirusFile" ("vid", "repo_id", "commit_id", "file_path", "has_deleted") SELECT "vid", "repo_id", "commit_id", "file_path", "has_handle" FROM "VirusFile_old";
DROP TABLE "VirusFile_old";
CREATE INDEX IF NOT EXISTS "VirusFile_repo_id_yewnci4gd" ON "VirusFile" ("repo_id");
CREATE INDEX IF NOT EXISTS "VirusFile_has_deleted_834ndyts" ON "VirusFile" ("has_deleted");
CREATE INDEX IF NOT EXISTS "VirusFile_has_ignored_d84tvuwg" ON "VirusFile" ("has_ignored");
CREATE TABLE IF NOT EXISTS "repo_auto_delete" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "repo_id" varchar(36) NOT NULL UNIQUE, "days" integer NOT NULL);

View File

@@ -54,6 +54,9 @@
#define PERM_EXPIRE_TIME 7200 /* 2 hours */
#define VIRINFO_EXPIRE_TIME 7200 /* 2 hours */
#define FS_ID_LIST_MAX_WORKERS 3
#define FS_ID_LIST_TOKEN_LEN 36
struct _HttpServer {
evbase_t *evbase;
evhtp_t *evhtp;
@@ -69,6 +72,11 @@ struct _HttpServer {
pthread_mutex_t vir_repo_info_cache_lock;
event_t *reap_timer;
GThreadPool *compute_fs_obj_id_pool;
GHashTable *fs_obj_ids;
pthread_mutex_t fs_obj_ids_lock;
};
typedef struct _HttpServer HttpServer;
@@ -115,6 +123,9 @@ const char *GET_HEAD_COMMITS_MULTI_REGEX = "^/repo/head-commits-multi";
const char *COMMIT_OPER_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/commit/[\\da-z]{40}";
const char *PUT_COMMIT_INFO_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/commit/[\\da-z]{40}";
const char *GET_FS_OBJ_ID_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/fs-id-list/.*";
const char *START_FS_OBJ_ID_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/start-fs-id-list/.*";
const char *QUERY_FS_OBJ_ID_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/query-fs-id-list/.*";
const char *RETRIEVE_FS_OBJ_ID_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/retrieve-fs-id-list/.*";
const char *BLOCK_OPER_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/block/[\\da-z]{40}";
const char *POST_CHECK_FS_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/check-fs";
const char *POST_CHECK_BLOCK_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/check-blocks";
@@ -1531,6 +1542,293 @@ out:
seaf_repo_unref (repo);
}
typedef struct ComputeObjTask {
HttpServer *htp_server;
char *token;
char *repo_id;
char *client_head;
char *server_head;
gboolean dir_only;
} ComputeObjTask;
typedef struct CalObjResult {
GList *list;
gboolean done;
} CalObjResult;
static void
free_compute_obj_task(ComputeObjTask *task)
{
if (!task)
return;
if (task->token)
g_free(task->token);
if (task->repo_id)
g_free(task->repo_id);
if (task->client_head)
g_free(task->client_head);
if (task->server_head)
g_free(task->server_head);
g_free(task);
}
static void
free_obj_cal_result (gpointer data)
{
CalObjResult *result = (CalObjResult *)data;
if (!result)
return;
if (result->list)
g_list_free (result->list);
g_free(result);
}
static void
compute_fs_obj_id (gpointer ptask, gpointer ppara)
{
SeafRepo *repo = NULL;
ComputeObjTask *task = ptask;
const char *client_head = task->client_head;
const char *server_head = task->server_head;
char *repo_id = task->repo_id;
gboolean dir_only = task->dir_only;
HttpServer *htp_server = task->htp_server;
CalObjResult *result = NULL;
pthread_mutex_lock (&htp_server->fs_obj_ids_lock);
result = g_hash_table_lookup (htp_server->fs_obj_ids, task->token);
pthread_mutex_unlock (&htp_server->fs_obj_ids_lock);
if (!result) {
goto out;
}
repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
if (!repo) {
seaf_warning ("Failed to find repo %.8s.\n", repo_id);
goto out;
}
if (calculate_send_object_list (repo, server_head, client_head, dir_only, &result->list) < 0) {
pthread_mutex_lock (&htp_server->fs_obj_ids_lock);
g_hash_table_remove (htp_server->fs_obj_ids, task->token);
pthread_mutex_unlock (&htp_server->fs_obj_ids_lock);
goto out;
}
result->done = TRUE;
out:
seaf_repo_unref (repo);
free_compute_obj_task(task);
}
static void
start_fs_obj_id_cb (evhtp_request_t *req, void *arg)
{
HttpServer *htp_server = arg;
char **parts;
char *repo_id;
gboolean dir_only = FALSE;
json_t *obj;
const char *server_head = evhtp_kv_find (req->uri->query, "server-head");
if (server_head == NULL || !is_object_id_valid (server_head)) {
char *error = "Invalid server-head parameter.\n";
evbuffer_add (req->buffer_out, error, strlen (error));
evhtp_send_reply (req, EVHTP_RES_BADREQ);
return;
}
const char *client_head = evhtp_kv_find (req->uri->query, "client-head");
if (client_head && !is_object_id_valid (client_head)) {
char *error = "Invalid client-head parameter.\n";
evbuffer_add (req->buffer_out, error, strlen (error));
evhtp_send_reply (req, EVHTP_RES_BADREQ);
return;
}
const char *dir_only_arg = evhtp_kv_find (req->uri->query, "dir-only");
if (dir_only_arg)
dir_only = TRUE;
parts = g_strsplit (req->uri->path->full + 1, "/", 0);
repo_id = parts[1];
int token_status = validate_token (htp_server, req, repo_id, NULL, FALSE);
if (token_status != EVHTP_RES_OK) {
evhtp_send_reply (req, token_status);
goto out;
}
char uuid[37];
char *new_token;
gen_uuid_inplace (uuid);
new_token = g_strndup(uuid, FS_ID_LIST_TOKEN_LEN);
CalObjResult *result = g_new0(CalObjResult, 1);
if (!result) {
evhtp_send_reply (req, EVHTP_RES_SERVERR);
goto out;
}
result->done = FALSE;
ComputeObjTask *task = g_new0 (ComputeObjTask, 1);
if (!task) {
evhtp_send_reply (req, EVHTP_RES_SERVERR);
goto out;
}
task->token = new_token;
task->dir_only = dir_only;
task->htp_server = htp_server;
task->repo_id = g_strdup(repo_id);
task->client_head = g_strdup(client_head);
task->server_head = g_strdup(server_head);
pthread_mutex_lock (&htp_server->fs_obj_ids_lock);
g_hash_table_insert (htp_server->fs_obj_ids, g_strdup(task->token), result);
pthread_mutex_unlock (&htp_server->fs_obj_ids_lock);
g_thread_pool_push (htp_server->compute_fs_obj_id_pool, task, NULL);
obj = json_object ();
json_object_set_new (obj, "token", json_string (new_token));
char *json_str = json_dumps (obj, JSON_COMPACT);
evbuffer_add (req->buffer_out, json_str, strlen(json_str));
evhtp_send_reply (req, EVHTP_RES_OK);
g_free (json_str);
json_decref (obj);
out:
g_strfreev (parts);
}
static void
query_fs_obj_id_cb (evhtp_request_t *req, void *arg)
{
json_t *obj;
const char *token = NULL;
CalObjResult *result = NULL;
char **parts;
char *repo_id = NULL;
HttpServer *htp_server = (HttpServer *)arg;
parts = g_strsplit (req->uri->path->full + 1, "/", 0);
repo_id = parts[1];
int token_status = validate_token (htp_server, req, repo_id, NULL, FALSE);
if (token_status != EVHTP_RES_OK) {
evhtp_send_reply (req, token_status);
goto out;
}
token = evhtp_kv_find (req->uri->query, "token");
if (!token || strlen(token)!=FS_ID_LIST_TOKEN_LEN) {
evhtp_send_reply (req, EVHTP_RES_BADREQ);
goto out;
}
obj = json_object ();
pthread_mutex_lock (&htp_server->fs_obj_ids_lock);
result = g_hash_table_lookup (htp_server->fs_obj_ids, token);
if (!result) {
pthread_mutex_unlock (&htp_server->fs_obj_ids_lock);
evhtp_send_reply (req, EVHTP_RES_NOTFOUND);
goto out;
} else {
if (!result->done) {
json_object_set_new (obj, "success", json_false());
} else {
json_object_set_new (obj, "success", json_true());
}
}
pthread_mutex_unlock (&htp_server->fs_obj_ids_lock);
json_object_set_new (obj, "token", json_string (token));
char *json_str = json_dumps (obj, JSON_COMPACT);
evbuffer_add (req->buffer_out, json_str, strlen(json_str));
evhtp_send_reply (req, EVHTP_RES_OK);
g_free (json_str);
out:
if (obj)
json_decref (obj);
g_strfreev (parts);
return;
}
static void
retrieve_fs_obj_id_cb (evhtp_request_t *req, void *arg)
{
char **parts;
const char *token = NULL;
char *repo_id = NULL;
GList *list = NULL;
CalObjResult *result = NULL;
HttpServer *htp_server = (HttpServer *)arg;
parts = g_strsplit (req->uri->path->full + 1, "/", 0);
repo_id = parts[1];
int token_status = validate_token (htp_server, req, repo_id, NULL, FALSE);
if (token_status != EVHTP_RES_OK) {
evhtp_send_reply (req, token_status);
goto out;
}
token = evhtp_kv_find (req->uri->query, "token");
if (!token || strlen(token)!=FS_ID_LIST_TOKEN_LEN) {
evhtp_send_reply (req, EVHTP_RES_BADREQ);
goto out;
}
pthread_mutex_lock (&htp_server->fs_obj_ids_lock);
result = g_hash_table_lookup (htp_server->fs_obj_ids, token);
if (!result) {
pthread_mutex_unlock (&htp_server->fs_obj_ids_lock);
evhtp_send_reply (req, EVHTP_RES_NOTFOUND);
return;
}
if (!result->done) {
pthread_mutex_unlock (&htp_server->fs_obj_ids_lock);
char *error = "The cauculation task is not completed.\n";
evbuffer_add (req->buffer_out, error, strlen(error));
evhtp_send_reply (req, EVHTP_RES_BADREQ);
return;
}
list = result->list;
pthread_mutex_unlock (&htp_server->fs_obj_ids_lock);
GList *ptr;
json_t *obj_array = json_array ();
for (ptr = list; ptr; ptr = ptr->next) {
json_array_append_new (obj_array, json_string (ptr->data));
g_free (ptr->data);
}
pthread_mutex_lock (&htp_server->fs_obj_ids_lock);
g_hash_table_remove (htp_server->fs_obj_ids, token);
pthread_mutex_unlock (&htp_server->fs_obj_ids_lock);
char *obj_list = json_dumps (obj_array, JSON_COMPACT);
evbuffer_add (req->buffer_out, obj_list, strlen (obj_list));
evhtp_send_reply (req, EVHTP_RES_OK);
g_free (obj_list);
json_decref (obj_array);
out:
g_strfreev (parts);
return;
}
static void
get_block_cb (evhtp_request_t *req, void *arg)
{
@@ -2346,6 +2644,18 @@ http_request_init (HttpServerStruct *server)
GET_FS_OBJ_ID_REGEX, get_fs_obj_id_cb,
priv);
evhtp_set_regex_cb (priv->evhtp,
START_FS_OBJ_ID_REGEX, start_fs_obj_id_cb,
priv);
evhtp_set_regex_cb (priv->evhtp,
QUERY_FS_OBJ_ID_REGEX, query_fs_obj_id_cb,
priv);
evhtp_set_regex_cb (priv->evhtp,
RETRIEVE_FS_OBJ_ID_REGEX, retrieve_fs_obj_id_cb,
priv);
evhtp_set_regex_cb (priv->evhtp,
BLOCK_OPER_REGEX, block_oper_cb,
priv);
@@ -2530,6 +2840,13 @@ seaf_http_server_new (struct _SeafileSession *session)
server->http_temp_dir = g_build_filename (session->seaf_dir, "httptemp", NULL);
priv->compute_fs_obj_id_pool = g_thread_pool_new (compute_fs_obj_id, NULL,
FS_ID_LIST_MAX_WORKERS, FALSE, NULL);
priv->fs_obj_ids = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, free_obj_cal_result);
pthread_mutex_init (&priv->fs_obj_ids_lock, NULL);
server->seaf_session = session;
server->priv = priv;