static int send_commit_start (CcnetProcessor *processor, int argc, char **argv) { GString *buf; int ret; TransferTask *task = ((SeafileSendcommitProc *)processor)->tx_task; ObjectList *ol = object_list_new (); ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, task->head, commit_collector, ol, FALSE); if (ret == FALSE) { object_list_free (ol); seaf_warning ("[sendcommit] Load commits error\n"); ccnet_processor_done (processor, FALSE); return -1; } g_return_val_if_fail (object_list_length(ol) != 0, -1); task->commits = ol; /* Send to_branch to the relay. */ buf = g_string_new (NULL); g_string_printf (buf, "remote %s seafile-recvcommit %s %s", processor->peer_id, task->to_branch, task->session_token); ccnet_processor_send_request (processor, buf->str); g_string_free (buf, TRUE); processor->state = INIT; return 0; }
static int verify_repo (SeafRepo *repo) { GList *branches, *ptr; SeafBranch *branch; int ret = 0; VerifyData data = {0}; data.truncate_time = seaf_repo_manager_get_repo_truncate_time (repo->manager, repo->id); branches = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo->id); if (branches == NULL) { seaf_warning ("[GC] Failed to get branch list of repo %s.\n", repo->id); return -1; } for (ptr = branches; ptr != NULL; ptr = ptr->next) { branch = ptr->data; gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, branch->commit_id, traverse_commit, &data); seaf_branch_unref (branch); if (!res) { ret = -1; break; } } g_list_free (branches); return ret; }
static void * compute_upload_commits_thread (void *vdata) { CcnetProcessor *processor = vdata; SeafileSendcommitV3Proc *proc = (SeafileSendcommitV3Proc *)processor; TransferTask *task = proc->tx_task; USE_PRIV; gboolean ret; priv->fast_forward = TRUE; ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, task->head, traverse_commit_fast_forward, processor, FALSE); if (!ret) { priv->compute_success = FALSE; return vdata; } if (priv->fast_forward) { priv->compute_success = TRUE; seaf_debug ("[sendcommt] Send commit after a fast forward merge.\n"); return vdata; } seaf_debug ("[sendcommit] Send commit after a real merge.\n"); if (compute_delta_commits (processor, task->head) < 0) { priv->compute_success = FALSE; return vdata; } priv->compute_success = TRUE; return vdata; }
static int migrate_repo (SeafRepo *repo) { MigrationData *data; int ret = 0; seaf_message ("Migrating data for repo %.8s.\n", repo->id); data = g_new0(MigrationData, 1); data->repo = repo; data->visited = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); gint64 truncate_time = seaf_repo_manager_get_repo_truncate_time (repo->manager, repo->id); data->truncate_time = truncate_time; gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, repo->id, repo->version, repo->head->commit_id, traverse_commit, data, FALSE); if (!res) { seaf_warning ("Migration of repo %s is not completed.\n", repo->id); ret = -1; } g_hash_table_destroy (data->visited); g_free (data); return ret; }
static void * collect_commit_id_thread (void *vprocessor) { CcnetProcessor *processor = vprocessor; USE_PRIV; priv->fast_forward = TRUE; if (seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, priv->head_commit_id, collect_id_fast_forward, processor, FALSE) < 0) { g_warning ("[putcommit] Failed to collect commit id.\n"); string_list_free (priv->id_list); priv->id_list = NULL; return vprocessor; } if (priv->fast_forward) { seaf_debug ("Send commits after a fast-forward merge.\n"); return vprocessor; } seaf_debug ("Send commits after a real merge.\n"); compute_delta_commits (processor, priv->head_commit_id); return vprocessor; }
/* * Merge "one" with commits in "twos". * The ancestors returned may not be ancestors for all the input commits. * They are common ancestors for one and some commits in twos array. */ static GList * merge_bases_many (SeafCommit *one, int n, SeafCommit **twos) { GHashTable *commit_hash; GList *result = NULL; SeafCommit *commit; int i; MergeTraverseData data; gboolean res; for (i = 0; i < n; i++) { if (one == twos[i]) return g_list_append (result, one); } /* First construct a hash table of all commit ids rooted at one. */ commit_hash = commit_tree_to_hash (one); if (!commit_hash) { g_warning ("Failed to load commit hash.\n"); return NULL; } data.commit_hash = commit_hash; data.result = NULL; for (i = 0; i < n; i++) { res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, twos[i]->repo_id, twos[i]->version, twos[i]->commit_id, get_merge_bases, &data, FALSE); if (!res) goto fail; } g_hash_table_destroy (commit_hash); result = data.result; if (!result || !result->next) return result; /* There are more than one. Try to find out independent ones. */ result = get_independent_commits (result); return result; fail: result = data.result; while (result) { commit = result->data; seaf_commit_unref (commit); result = g_list_delete_link (result, result); } g_hash_table_destroy (commit_hash); return NULL; }
/* * Check whether the current head of @repo is consistent (including fs and block), * if not, find and reset its head to the last consistent commit. * Note that this procedure will not work with a corrupted commit object. */ static void check_and_reset_consistent_state (SeafRepo *repo) { FsckRes res; SeafCommit *rep_commit; SeafCommit *new_commit; seaf_message ("Checking file system integrity of repo %s(%.8s)...\n", repo->name, repo->id); memset (&res, 0, sizeof(res)); res.repo = repo; res.existing_blocks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, repo->id, repo->version, repo->head->commit_id, check_fs_integrity, &res, TRUE); g_hash_table_destroy (res.existing_blocks); if (!res.consistent_head) { recover_corrupted_repo_head (repo->id); return; } /* If the current head is not consistent, reset it. */ if (strcmp (res.consistent_head, repo->head->commit_id) != 0) { rep_commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, repo->version, res.consistent_head); if (rep_commit) { new_commit = cre_commit_from_parent (repo->id, rep_commit); if (new_commit == NULL) { seaf_warning ("Failed to update branch head.\n"); } else { seaf_message ("Resetting head of repo %.8s to commit %.8s.\n", repo->id, new_commit->commit_id); seaf_branch_set_commit (repo->head, new_commit->commit_id); if (seaf_branch_manager_update_branch (seaf->branch_mgr, repo->head) < 0) { seaf_warning ("Failed to update branch head.\n"); } else { seaf_commit_manager_add_commit (seaf->commit_mgr, new_commit); } seaf_commit_unref (new_commit); } seaf_commit_unref (rep_commit); } else { seaf_warning ("Failed to update branch head.\n"); } } g_free (res.consistent_head); }
static int compute_delta_commits (CcnetProcessor *processor, const char *head) { gboolean ret; USE_PRIV; string_list_free (priv->id_list); priv->id_list = NULL; priv->commit_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /* When putting commits, the remote head commit must exists. */ ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, priv->repo_id, priv->repo_version, priv->remote_commit_id, collect_id_remote, processor, FALSE); if (!ret) { seaf_warning ("[putcommit] Failed to traverse remote branch.\n"); string_list_free (priv->id_list); priv->id_list = NULL; return -1; } ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, priv->repo_id, priv->repo_version, head, compute_delta, processor, FALSE); if (!ret) { seaf_warning ("[putcommit] Failed to compute delta commits.\n"); string_list_free (priv->id_list); priv->id_list = NULL; return -1; } return 0; }
static int send_commit_ids (CcnetProcessor *processor, const char *head) { char buf[2048]; char *ptr = buf; int i, count = 0; int ret; ObjectList *ol = object_list_new (); ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, head, commit_collector, ol); if (ret == FALSE) { object_list_free (ol); g_warning ("[putcommit] Load commits error\n"); ccnet_processor_send_response ( processor, SC_NOT_FOUND, SS_NOT_FOUND, NULL, 0); ccnet_processor_done (processor, FALSE); return -1; } int ollen = object_list_length(ol); g_assert (ollen != 0); for (i = 0; i < ollen; i++) { memcpy (ptr, g_ptr_array_index(ol->obj_ids, i), 40); ptr += 40; *ptr++ = '\n'; if (++count == 48) { *ptr = '\0'; g_debug ("[putcommit] Send commit ids:\n%s", buf); ccnet_processor_send_response (processor, SC_COMMIT_IDS, SS_COMMIT_IDS, buf, 41 * count + 1); ptr = buf; count = 0; } } if (count) { *ptr = '\0'; g_debug ("[putcommit] Send commit ids:\n%s", buf); ccnet_processor_send_response (processor, SC_COMMIT_IDS, SS_COMMIT_IDS, buf, 41 * count + 1); } g_debug ("[putcommit] Sent commit ids.\n"); ccnet_processor_send_response (processor, SC_END, SS_END, NULL, 0); return 0; }
static int validate_branch(SeafBranch *branch) { if (!branch) return -1; g_message ("Checking for branch %s\n", branch->name); if (!seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, branch->commit_id, validate_commit, NULL)) { return -1; } return 0; }
static int compute_delta_commits (CcnetProcessor *processor, const char *head) { gboolean ret; TransferTask *task = ((SeafileSendcommitV3Proc *)processor)->tx_task; USE_PRIV; string_list_free (priv->id_list); priv->id_list = NULL; object_list_free (task->fs_roots); task->fs_roots = object_list_new (); object_list_free (task->commits); task->commits = object_list_new (); priv->commit_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, priv->remote_id, traverse_commit_remote, processor, FALSE); if (!ret) { return -1; } ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, head, compute_delta, processor, FALSE); if (!ret) { return -1; } return 0; }
static void send_commits (CcnetProcessor *processor, const char *head) { gboolean ret; ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, head, traverse_commit, processor); if (!ret) { ccnet_processor_send_update (processor, SC_NOT_FOUND, SS_NOT_FOUND, NULL, 0); ccnet_processor_done (processor, FALSE); return; } send_one_commit (processor); }
static gboolean check_fast_forward (SeafCommit *head, const char *root_id) { CompareAux *aux = g_new0 (CompareAux, 1); gboolean ret; memcpy (aux->root_id, root_id, 41); if (!seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, head->commit_id, compare_root, aux)) { g_free (aux); return FALSE; } ret = aux->fast_forward; g_free (aux); return ret; }
static void * collect_commit_id_thread (void *vprocessor) { CcnetProcessor *processor = vprocessor; USE_PRIV; SeafRepo *repo; repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); if (!repo) { seaf_warning ("Failed to get repo %s.\n", priv->repo_id); priv->id_list = NULL; return vprocessor; } priv->repo_version = repo->version; priv->fast_forward = TRUE; if (seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, repo->id, repo->version, priv->head_commit_id, collect_id_fast_forward, processor, FALSE) < 0) { seaf_warning ("[putcommit] Failed to collect commit id.\n"); string_list_free (priv->id_list); priv->id_list = NULL; goto out; } if (priv->fast_forward) { seaf_debug ("Send commits after a fast-forward merge.\n"); goto out; } seaf_debug ("Send commits after a real merge.\n"); compute_delta_commits (processor, priv->head_commit_id); out: seaf_repo_unref (repo); return vprocessor; }
static GHashTable * commit_tree_to_hash (SeafCommit *head) { GHashTable *hash; gboolean res; hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, head->commit_id, add_to_commit_hash, hash); if (!res) goto fail; return hash; fail: g_hash_table_destroy (hash); return NULL; }
static void send_commits (CcnetProcessor *processor, const char *head) { TransferTask *task = ((SeafileSendcommitV2Proc *)processor)->tx_task; gboolean ret; ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, task->repo_id, task->repo_version, head, traverse_commit, processor, FALSE); if (!ret) { ccnet_processor_send_update (processor, SC_NOT_FOUND, SS_NOT_FOUND, NULL, 0); ccnet_processor_done (processor, FALSE); } ccnet_processor_send_update (processor, SC_END, SS_END, NULL, 0); ccnet_processor_done (processor, TRUE); }
GList * seaf_repo_get_commits (SeafRepo *repo) { GList *branches; GList *ptr; SeafBranch *branch; GList *commits = NULL; branches = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo->id); if (branches == NULL) { g_warning ("Failed to get branch list of repo %s.\n", repo->id); return NULL; } for (ptr = branches; ptr != NULL; ptr = ptr->next) { branch = ptr->data; gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, repo->id, repo->version, branch->commit_id, collect_commit, &commits, FALSE); if (!res) { for (ptr = commits; ptr != NULL; ptr = ptr->next) seaf_commit_unref ((SeafCommit *)(ptr->data)); g_list_free (commits); goto out; } } commits = g_list_reverse (commits); out: for (ptr = branches; ptr != NULL; ptr = ptr->next) { seaf_branch_unref ((SeafBranch *)ptr->data); } return commits; }