From 4489fbfa2b45fc92d1bc8de77cd81459f98472c4 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 15 May 2008 13:50:34 +0200 Subject: [PATCH] Implement the reconciler. --- client/csync_client.c | 12 +++- src/CMakeLists.txt | 1 + src/csync.c | 49 +++++++++++++++- src/csync_reconcile.c | 133 ++++++++++++++++++++++++++++++++++++++++++ src/csync_reconcile.h | 28 +++++++++ 5 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 src/csync_reconcile.c create mode 100644 src/csync_reconcile.h diff --git a/client/csync_client.c b/client/csync_client.c index e116a09b55..2da98400cc 100644 --- a/client/csync_client.c +++ b/client/csync_client.c @@ -160,10 +160,15 @@ int main(int argc, char **argv) { printf("Version: %s\n", csync_version()); if (arguments.update) { - csync_update(csync); + if (csync_update(csync) < 0) { + goto err; + } } if (arguments.reconcile) { + if (csync_reconcile(csync) < 0) { + goto err; + } } if (arguments.propagate) { @@ -176,5 +181,10 @@ int main(int argc, char **argv) { csync_destroy(csync); return 0; +err: + perror("csync"); + csync_destroy(csync); + + return 1; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b445bfbfd0..c55d7f3b25 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,6 +41,7 @@ set(csync_SRCS csync_exclude.c csync_journal.c csync_lock.c + csync_reconcile.c csync_time.c csync_util.c csync_update.c diff --git a/src/csync.c b/src/csync.c index 9d9f8f7793..cd827319d9 100644 --- a/src/csync.c +++ b/src/csync.c @@ -38,6 +38,7 @@ #include "csync_util.h" #include "csync_update.h" +#include "csync_reconcile.h" #include "vio/csync_vio.h" @@ -48,7 +49,7 @@ static int key_cmp(const void *key, const void *data) { uint64_t a; csync_file_stat_t *b; - a = POINTER_TO_INT(key); + a = (uint64_t) key; b = (csync_file_stat_t *) data; if (a < b->phash) { @@ -334,6 +335,52 @@ int csync_update(CSYNC *ctx) { return 0; } +int csync_reconcile(CSYNC *ctx) { + int rc = -1; + time_t start, finish; + + if (ctx == NULL) { + errno = EBADF; + return -1; + } + + /* Reconciliation for local replica */ + time(&start); + ctx->current = LOCAL_REPLICA; + ctx->replica = ctx->local.type; + + rc = csync_reconcile_updates(ctx); + + time(&finish); + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, + "Reconciliation for local replica took %.2f seconds", + difftime(finish, start)); + + if (rc < 0) { + return -1; + } + + /* Reconciliation for local replica */ + time(&start); + ctx->current = REMOTE_REPLCIA; + ctx->replica = ctx->remote.type; + + rc = csync_reconcile_updates(ctx); + + time(&finish); + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, + "Reconciliation for local replica took %.2f seconds", + difftime(finish, start)); + + if (rc < 0) { + return -1; + } + + ctx->status |= CSYNC_RECONCILE; + + return 0; +} + static void tree_destructor(void *data) { csync_file_stat_t *freedata = NULL; diff --git a/src/csync_reconcile.c b/src/csync_reconcile.c new file mode 100644 index 0000000000..dcc16c3a0b --- /dev/null +++ b/src/csync_reconcile.c @@ -0,0 +1,133 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008 by Andreas Schneider + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * vim: ts=2 sw=2 et cindent + */ + +#include "csync_private.h" +#include "csync_reconcile.h" +#include "csync_util.h" + +#define CSYNC_LOG_CATEGORY_NAME "csync.reconciler" +#include "csync_log.h" + +static int csync_merge_algorithm_visitor(void *obj, void *data) { + csync_file_stat_t *cur = NULL; + csync_file_stat_t *other = NULL; + CSYNC *ctx = NULL; + c_rbtree_t *tree = NULL; + c_rbnode_t *node = NULL; + + cur = (csync_file_stat_t *) obj; + ctx = (CSYNC *) data; + + /* we need the opposite tree! */ + switch (ctx->current) { + case LOCAL_REPLICA: + tree = ctx->remote.tree; + break; + case REMOTE_REPLCIA: + tree = ctx->local.tree; + break; + default: + break; + } + + node = c_rbtree_find(tree, (void *) cur->phash); + /* file only found on current replica */ + if (node == NULL) { + switch(cur->instruction) { + /* file has been modified */ + case CSYNC_INSTRUCTION_EVAL: + cur->instruction = CSYNC_INSTRUCTION_NEW; + break; + /* file has been removed on the opposite replica */ + case CSYNC_INSTRUCTION_NONE: + cur->instruction = CSYNC_INSTRUCTION_REMOVE; + break; + case CSYNC_INSTRUCTION_RENAME: + cur->instruction = CSYNC_INSTRUCTION_NEW; + break; + default: + break; + } + } else { + /* + * file found on the other replica + */ + other = (csync_file_stat_t *) node->data; + + switch (cur->instruction) { + /* file on current replica is new */ + case CSYNC_INSTRUCTION_NEW: + /* file on current replica has been modified */ + case CSYNC_INSTRUCTION_EVAL: + switch (other->instruction) { + /* file on other replica is new too */ + case CSYNC_INSTRUCTION_NEW: + if (cur->modtime > other->modtime) { + cur->instruction = CSYNC_INSTRUCTION_SYNC; + } + cur->instruction = CSYNC_INSTRUCTION_NONE; + break; + /* file on other replica has changed too */ + case CSYNC_INSTRUCTION_EVAL: + /* file on current replica is newer */ + if (cur->modtime > other->modtime) { + cur->instruction = CSYNC_INSTRUCTION_SYNC; + } + /* file on opposite replica is newer */ + cur->instruction = CSYNC_INSTRUCTION_REMOVE; + break; + /* file on the other replica has not been modified */ + case CSYNC_INSTRUCTION_NONE: + cur->instruction = CSYNC_INSTRUCTION_SYNC; + break; + default: + break; + } + default: + break; + } + } + + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s, instruction: %s", cur->path, csync_instruction_str(cur->instruction)); + return 0; +} + +int csync_reconcile_updates(CSYNC *ctx) { + int rc = -1; + c_rbtree_t *tree = NULL; + + switch (ctx->current) { + case LOCAL_REPLICA: + tree = ctx->local.tree; + break; + case REMOTE_REPLCIA: + tree = ctx->remote.tree; + break; + default: + break; + } + + rc = c_rbtree_walk(tree, (void *) ctx, csync_merge_algorithm_visitor); + + return 0; +} + diff --git a/src/csync_reconcile.h b/src/csync_reconcile.h new file mode 100644 index 0000000000..6f64c408bc --- /dev/null +++ b/src/csync_reconcile.h @@ -0,0 +1,28 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008 by Andreas Schneider + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * vim: ft=c.doxygen ts=2 sw=2 et cindent + */ + +#ifndef _CSYNC_RECONCILE_H +#define _CSYNC_RECONCILE_H + +int csync_reconcile_updates(CSYNC *ctx); + +#endif /* _CSYNC_RECONCILE_H */