Beispiel #1
0
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;
}
Beispiel #2
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;
}
Beispiel #4
0
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;
}
Beispiel #6
0
/*
 * 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;
}
Beispiel #7
0
/*
 * 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);
}
Beispiel #8
0
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;
}
Beispiel #9
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;
}
Beispiel #10
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;
}
Beispiel #12
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);
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
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;
}
Beispiel #16
0
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);
}
Beispiel #17
0
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;
}