00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "engine.h"
00022 #include "engine_internals.h"
00023
00028
00029 static OSyncMappingEntry *_osync_find_next_diff(OSyncMapping *mapping, OSyncMappingEntry *orig_entry)
00030 {
00031 GList *e;
00032 for (e = mapping->entries; e; e = e->next) {
00033 OSyncMappingEntry *entry = e->data;
00034 if (osync_change_get_changetype(entry->change) == CHANGE_UNKNOWN)
00035 continue;
00036 if ((entry->change != orig_entry->change) && osync_change_compare(orig_entry->change, entry->change) != CONV_DATA_SAME)
00037 return entry;
00038 }
00039 osync_debug("MAP", 3, "Could not find next diff");
00040 return NULL;
00041 }
00042
00043 static OSyncMappingEntry *_osync_find_next_same(OSyncMapping *mapping, OSyncMappingEntry *orig_entry)
00044 {
00045 GList *e;
00046 for (e = mapping->entries; e; e = e->next) {
00047 OSyncMappingEntry *entry = e->data;
00048 if (osync_change_get_changetype(entry->change) == CHANGE_UNKNOWN)
00049 continue;
00050 if ((entry->change != orig_entry->change) && osync_change_compare(orig_entry->change, entry->change) == CONV_DATA_SAME)
00051 return entry;
00052 }
00053 osync_debug("MAP", 3, "Could not find next diff");
00054 return NULL;
00055 }
00056
00057 static OSyncMappingEntry *_osync_change_clone(OSyncEngine *engine, OSyncMapping *new_mapping, OSyncMappingEntry *comp_entry)
00058 {
00059 OSyncMappingEntry *newentry = osengine_mappingentry_new(NULL);
00060 newentry->change = osync_change_new();
00061 newentry->client = comp_entry->client;
00062 osengine_mapping_add_entry(new_mapping, newentry);
00063 osengine_mappingview_add_entry(comp_entry->view, newentry);
00064 osengine_mappingentry_update(newentry, comp_entry->change);
00065 osync_change_set_uid(newentry->change, osync_change_get_uid(comp_entry->change));
00066 osync_flag_set(newentry->fl_has_data);
00067 osync_flag_set(newentry->fl_mapped);
00068 osync_flag_set(newentry->fl_has_info);
00069 osync_flag_set(newentry->fl_dirty);
00070 osync_flag_unset(newentry->fl_synced);
00071 osync_change_save(newentry->change, TRUE, NULL);
00072 return newentry;
00073 }
00074
00075 osync_bool osync_change_elevate(OSyncEngine *engine, OSyncChange *change, int level)
00076 {
00077 osync_debug("MAP", 3, "elevating change %s (%p) to level %i", osync_change_get_uid(change), change, level);
00078 int i = 0;
00079 for (i = 0; i < level; i++) {
00080 if (!osync_change_duplicate(change))
00081 return FALSE;
00082 }
00083 osync_debug("MAP", 3, "change after being elevated %s (%p)", osync_change_get_uid(change), change);
00084 osync_change_save(change, TRUE, NULL);
00085 return TRUE;
00086 }
00087
00088 osync_bool osync_change_check_level(OSyncEngine *engine, OSyncMappingEntry *entry)
00089 {
00090 GList *c;
00091 osync_debug("MAP", 3, "checking level for change %s (%p)", osync_change_get_uid(entry->change), entry);
00092 for (c = engine->clients; c; c = c->next) {
00093 OSyncClient *client = c->data;
00094 OSyncMappingView *view = osengine_mappingtable_find_view(engine->maptable, client->member);
00095 if (!osengine_mappingview_uid_is_unique(view, entry, TRUE))
00096 return FALSE;
00097 }
00098 return TRUE;
00099 }
00100
00101 static int prod(int n)
00102 {
00103 int ret;
00104 for (ret = 0; n > 0; n--)
00105 ret += n;
00106 return ret;
00107 }
00108
00109 void osengine_mapping_multiply_master(OSyncEngine *engine, OSyncMapping *mapping)
00110 {
00111 osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, engine, mapping);
00112 g_assert(engine);
00113
00114 OSyncMappingTable *table = engine->maptable;
00115 OSyncMappingEntry *entry = NULL;
00116 OSyncMappingEntry *master = NULL;
00117
00118 master = mapping->master;
00119 g_assert(master);
00120 if (osync_flag_is_not_set(master->fl_dirty))
00121 osync_flag_set(master->fl_synced);
00122 else
00123 osync_flag_attach(master->fl_committed, table->engine->cmb_committed_all);
00124
00125
00126 GList *v;
00127 for (v = table->views; v; v = v->next) {
00128 OSyncMappingView *view = v->data;
00129
00130 entry = osengine_mapping_find_entry(mapping, NULL, view);
00131 if (entry == master)
00132 continue;
00133 if (entry && (osync_change_compare(entry->change, master->change) == CONV_DATA_SAME)) {
00134 if (osync_flag_is_not_set(entry->fl_dirty))
00135 osync_flag_set(entry->fl_synced);
00136 continue;
00137 }
00138 if (!entry) {
00139 entry = osengine_mappingentry_new(NULL);
00140 entry->change = osync_change_new();
00141 entry->client = view->client;
00142 osengine_mappingview_add_entry(view, entry);
00143 osengine_mappingentry_update(entry, master->change);
00144 osync_change_set_uid(entry->change, osync_change_get_uid(master->change));
00145 osync_change_set_member(entry->change, view->client->member);
00146 osengine_mapping_add_entry(mapping, entry);
00147 } else {
00148 osync_bool had_data = osync_change_has_data(entry->change);
00149 osengine_mappingentry_update(entry, master->change);
00150 if (osync_change_get_changetype(entry->change) == CHANGE_ADDED || osync_change_get_changetype(entry->change) == CHANGE_UNKNOWN) {
00151 osync_change_set_changetype(entry->change, CHANGE_MODIFIED);
00152 }
00153
00154 if (osync_member_get_slow_sync(view->client->member, osync_objtype_get_name(osync_change_get_objtype(entry->change))) && !had_data) {
00155 osync_change_set_changetype(entry->change, CHANGE_ADDED);
00156 }
00157 }
00158 if (osync_flag_is_set(view->client->fl_sent_changes)) {
00159
00160 osync_flag_set(entry->fl_dirty);
00161 osync_flag_set(entry->fl_has_data);
00162 osync_flag_set(entry->fl_mapped);
00163 osync_flag_set(entry->fl_has_info);
00164 osync_flag_unset(entry->fl_synced);
00165 OSyncError *error = NULL;
00166 osync_change_save(entry->change, TRUE, &error);
00167 osync_flag_attach(entry->fl_committed, table->engine->cmb_committed_all);
00168 }
00169 }
00170
00171 OSyncError *error = NULL;
00172 osync_change_save(master->change, TRUE, &error);
00173
00174 osync_flag_set(mapping->fl_multiplied);
00175 osync_trace(TRACE_EXIT, "%s", __func__);
00176 }
00177
00178
00179
00180 void osengine_mapping_check_conflict(OSyncEngine *engine, OSyncMapping *mapping)
00181 {
00182 osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, engine, mapping);
00183 GList *e;
00184 GList *n;
00185 osync_bool is_conflict = FALSE;
00186 int is_same = 0;
00187 OSyncMappingEntry *leftentry = NULL;
00188 OSyncMappingEntry *rightentry = NULL;
00189
00190 g_assert(engine != NULL);
00191 g_assert(mapping != NULL);
00192 g_assert(!mapping->master);
00193
00194 for (e = mapping->entries; e; e = e->next) {
00195 leftentry = e->data;
00196 if (osync_change_get_changetype(leftentry->change) == CHANGE_UNKNOWN)
00197 continue;
00198 mapping->master = leftentry;
00199 for (n = e->next; n; n = n->next) {
00200 rightentry = n->data;
00201 if (osync_change_get_changetype(rightentry->change) == CHANGE_UNKNOWN)
00202 continue;
00203
00204 if (osync_change_compare(leftentry->change, rightentry->change) != CONV_DATA_SAME) {
00205 is_conflict = TRUE;
00206 goto conflict;
00207 } else {
00208 is_same++;
00209 }
00210 }
00211 }
00212
00213 conflict:
00214 if (is_conflict) {
00215
00216 osync_debug("MAP", 2, "Got conflict for mapping %p", mapping);
00217 osync_status_conflict(engine, mapping);
00218 osync_flag_set(mapping->fl_chkconflict);
00219 osync_trace(TRACE_EXIT, "%s: Got conflict", __func__);
00220 return;
00221 }
00222 g_assert(mapping->master);
00223 osync_flag_set(mapping->fl_chkconflict);
00224
00225
00226 osync_flag_set(mapping->fl_solved);
00227
00228 if (is_same == prod(g_list_length(engine->maptable->views) - 1)) {
00229 osync_trace(TRACE_INTERNAL, "No need to sync. All entries are the same");
00230 osync_flag_set(mapping->cmb_synced);
00231 osync_flag_set(mapping->fl_multiplied);
00232 }
00233
00234 send_mapping_changed(engine, mapping);
00235 osync_trace(TRACE_EXIT, "%s: No conflict", __func__);
00236 }
00237
00238 static OSyncMapping *_osengine_mapping_find(OSyncMappingTable *table, OSyncMappingEntry *orig_entry)
00239 {
00240 GList *i;
00241 GList *n;
00242 osync_bool mapping_found = FALSE;
00243
00244 for (i = table->mappings; i; i = i->next) {
00245 OSyncMapping *mapping = i->data;
00246
00247 if (!osengine_mapping_find_entry(mapping, NULL, orig_entry->view)) {
00248 mapping_found = TRUE;
00249 for (n = mapping->entries; n; n = n->next) {
00250 OSyncMappingEntry *entry = n->data;
00251 if (osync_change_compare_data(entry->change, orig_entry->change) == CONV_DATA_MISMATCH) {
00252 mapping_found = FALSE;
00253 continue;
00254 }
00255 }
00256 if (mapping_found)
00257 return mapping;
00258 }
00259 }
00260 return NULL;
00261 }
00262
00263 void osengine_change_map(OSyncEngine *engine, OSyncMappingEntry *entry)
00264 {
00265 osync_trace(TRACE_ENTRY, "osengine_change_map(%p, %p)", engine, entry);
00266 OSyncMapping *mapping = NULL;
00267 if (!(mapping = _osengine_mapping_find(engine->maptable, entry))) {
00268 mapping = osengine_mapping_new(engine->maptable);
00269 osync_flag_unset(mapping->fl_chkconflict);
00270 osync_flag_unset(mapping->fl_multiplied);
00271 mapping->id = osengine_mappingtable_get_next_id(engine->maptable);
00272 osync_trace(TRACE_INTERNAL, "No previous mapping found. Creating new one: %p", mapping);
00273 }
00274 osengine_mapping_add_entry(mapping, entry);
00275 osync_flag_set(entry->fl_mapped);
00276 osync_change_save(entry->change, FALSE, NULL);
00277 osync_trace(TRACE_EXIT, "osengine_change_map");
00278 }
00279
00289
00296 void osengine_mapping_duplicate(OSyncEngine *engine, OSyncMapping *dupe_mapping)
00297 {
00298 osync_trace(TRACE_ENTRY, "osengine_mapping_duplicate(%p, %p)", engine, dupe_mapping);
00299 g_assert(dupe_mapping);
00300 int elevation = 0;
00301 OSyncMappingEntry *orig_entry = NULL;
00302 OSyncMappingEntry *first_diff_entry = NULL;
00303 OSyncMappingEntry *next_entry = NULL;
00304 OSyncMapping *new_mapping = NULL;
00305
00306
00307 GList *entries, *e;
00308 entries = g_list_copy(dupe_mapping->entries);
00309 for (e = entries; e; e = e->next) {
00310 OSyncMappingEntry *entry = e->data;
00311 if (osync_change_get_changetype(entry->change) == CHANGE_DELETED) {
00312 osync_change_delete(entry->change, NULL);
00313 osengine_mappingentry_free(entry);
00314 }
00315 }
00316 g_list_free(entries);
00317
00318
00319 GList *i = dupe_mapping->entries;
00320 do {
00321 orig_entry = i->data;
00322 i = i->next;
00323 } while (osync_change_get_changetype(orig_entry->change) != CHANGE_MODIFIED && osync_change_get_changetype(orig_entry->change) != CHANGE_ADDED);
00324 dupe_mapping->master = orig_entry;
00325 osync_change_set_changetype(orig_entry->change, CHANGE_MODIFIED);
00326
00327
00328
00329
00330
00331
00332
00333 while ((first_diff_entry = _osync_find_next_diff(dupe_mapping, orig_entry))) {
00334
00335 elevation = 0;
00336 new_mapping = osengine_mapping_new(engine->maptable);
00337 new_mapping->id = osengine_mappingtable_get_next_id(engine->maptable);
00338 osync_flag_unset(new_mapping->cmb_synced);
00339 osync_flag_set(new_mapping->fl_chkconflict);
00340 osync_flag_unset(new_mapping->fl_multiplied);
00341 osync_flag_set(new_mapping->fl_solved);
00342 send_mapping_changed(engine, new_mapping);
00343 osync_debug("MAP", 3, "Created new mapping for duplication %p with mappingid %lli", new_mapping, new_mapping->id);
00344
00345
00346
00347 OSyncMappingEntry *newentry = osengine_mappingentry_copy(first_diff_entry);
00348 new_mapping->master = newentry;
00349 osengine_mapping_add_entry(new_mapping, newentry);
00350 osync_change_set_changetype(newentry->change, CHANGE_ADDED);
00351 osync_flag_set(newentry->fl_has_data);
00352 osync_flag_set(newentry->fl_mapped);
00353 osync_flag_set(newentry->fl_has_info);
00354 osync_flag_set(newentry->fl_dirty);
00355 osync_flag_unset(newentry->fl_synced);
00356
00357
00358
00359
00360 do {
00361 if (!osync_change_elevate(engine, newentry->change, 1))
00362 break;
00363 elevation += 1;
00364 } while (!osync_change_check_level(engine, newentry));
00365 OSyncError *error = NULL;
00366 osync_change_save(newentry->change, TRUE, &error);
00367
00368
00369
00370
00371 while ((next_entry = _osync_find_next_same(dupe_mapping, first_diff_entry))) {
00372 newentry = _osync_change_clone(engine, new_mapping, first_diff_entry);
00373 osync_change_elevate(engine, newentry->change, elevation);
00374 osengine_mappingentry_update(orig_entry, next_entry->change);
00375 osync_change_save(next_entry->change, TRUE, NULL);
00376 }
00377
00378
00379
00380 osync_change_set_changetype(first_diff_entry->change, CHANGE_UNKNOWN);
00381
00382
00383 send_mapping_changed(engine, new_mapping);
00384 }
00385
00386
00387 osync_flag_set(dupe_mapping->fl_solved);
00388 send_mapping_changed(engine, dupe_mapping);
00389 osync_trace(TRACE_EXIT, "osengine_mapping_duplicate");
00390 }
00391
00401 void osengine_mapping_solve(OSyncEngine *engine, OSyncMapping *mapping, OSyncChange *change)
00402 {
00403 osync_trace(TRACE_ENTRY, "osengine_mapping_solve(%p, %p, %p)", engine, mapping, change);
00404 OSyncMappingEntry *entry = osengine_mapping_find_entry(mapping, change, NULL);
00405 mapping->master = entry;
00406 osync_flag_set(mapping->fl_solved);
00407 send_mapping_changed(engine, mapping);
00408 osync_trace(TRACE_EXIT, "osengine_mapping_solve");
00409 }
00410
00420 osync_bool osengine_mapping_ignore_conflict(OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error)
00421 {
00422 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, engine, mapping, error);
00423
00424 if (!osengine_mapping_ignore_supported(engine, mapping)) {
00425 osync_error_set(error, OSYNC_ERROR_GENERIC, "Ignore is not supported for this mapping");
00426 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00427 return FALSE;
00428 }
00429
00430 GList *e = NULL;
00431 for (e = mapping->entries; e; e = e->next) {
00432 OSyncMappingEntry *entry = e->data;
00433 osync_trace(TRACE_INTERNAL, "Adding %p to logchanges", entry);
00434 OSyncError *error = NULL;
00435 if (osync_change_get_changetype(entry->change) != CHANGE_UNKNOWN)
00436 osync_group_save_changelog(engine->group, entry->change, &error);
00437 }
00438
00439
00440
00441 osync_flag_set(mapping->fl_multiplied);
00442 osync_flag_set(mapping->cmb_synced);
00443 osync_flag_set(mapping->cmb_has_info);
00444 osync_trace(TRACE_EXIT, "%s", __func__);
00445 return TRUE;
00446 }
00447
00461 osync_bool osengine_mapping_ignore_supported(OSyncEngine *engine, OSyncMapping *mapping)
00462 {
00463 osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, engine, mapping);
00464
00465 int i, count = 0;
00466 OSyncChange *change = NULL;
00467 OSyncMember *member = NULL;
00468 OSyncObjType *objtype = NULL;
00469
00470 count = osengine_mapping_num_changes(mapping);
00471 for (i = 0; i < count; ++i) {
00472 change = osengine_mapping_nth_change(mapping, i);
00473 objtype = osync_change_get_objtype(change);
00474
00475 member = osync_change_get_member(change);
00476
00477 if (!osync_member_has_read_function(member, objtype)) {
00478 osync_trace(TRACE_EXIT, "%s: Ignore NOT supported", __func__);
00479 return FALSE;
00480 }
00481 }
00482
00483 osync_trace(TRACE_EXIT, "%s: Ignore supported", __func__);
00484 return TRUE;
00485 }
00486
00499 osync_bool osengine_mapping_solve_latest(OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error)
00500 {
00501 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, engine, mapping, error);
00502
00503 time_t time = 0;
00504 time_t latesttime = 0;
00505 osync_bool preveq = FALSE;
00506
00507 GList *e = NULL;
00508 for (e = mapping->entries; e; e = e->next) {
00509 OSyncMappingEntry *entry = e->data;
00510
00511 if (osync_change_get_changetype(entry->change) != CHANGE_UNKNOWN) {
00512 time = osync_change_get_revision(entry->change, error);
00513 if (time == -1) {
00514 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00515 mapping->master = NULL;
00516 return FALSE;
00517 }
00518
00519 if (time > latesttime) {
00520 latesttime = time;
00521 mapping->master = entry;
00522 preveq = FALSE;
00523 } else if (time == latesttime)
00524 preveq = TRUE;
00525 }
00526 }
00527
00528 if (preveq == TRUE) {
00529 osync_error_set(error, OSYNC_ERROR_GENERIC, "Could not decide for one entry. Timestamps where equal");
00530 mapping->master = NULL;
00531 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00532 return FALSE;
00533 }
00534
00535 osync_flag_set(mapping->fl_solved);
00536 send_mapping_changed(engine, mapping);
00537
00538 osync_trace(TRACE_EXIT, "%s: %p", __func__, mapping->master);
00539 return TRUE;
00540 }
00541
00554 osync_bool osengine_mapping_check_timestamps(OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error)
00555 {
00556 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, engine, mapping, error);
00557
00558 time_t time = 0;
00559 time_t latesttime = 0;
00560 osync_bool preveq = FALSE;
00561
00562 GList *e = NULL;
00563 for (e = mapping->entries; e; e = e->next) {
00564 OSyncMappingEntry *entry = e->data;
00565
00566 if (osync_change_get_changetype(entry->change) != CHANGE_UNKNOWN) {
00567 time = osync_change_get_revision(entry->change, error);
00568 if (time == -1) {
00569 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00570 return FALSE;
00571 }
00572
00573 if (time > latesttime) {
00574 latesttime = time;
00575 preveq = FALSE;
00576 } else if (time == latesttime)
00577 preveq = TRUE;
00578 }
00579 }
00580
00581 if (preveq == TRUE) {
00582 osync_error_set(error, OSYNC_ERROR_GENERIC, "Could not decide for one entry. Timestamps where equal");
00583 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00584 return FALSE;
00585 }
00586
00587 osync_trace(TRACE_EXIT, "%s", __func__);
00588 return TRUE;
00589 }
00590
00601 void osengine_mapping_solve_updated(OSyncEngine *engine, OSyncMapping *mapping, OSyncChange *change)
00602 {
00603 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, engine, mapping, change);
00604 OSyncMappingEntry *entry = osengine_mapping_find_entry(mapping, change, NULL);
00605 mapping->master = entry;
00606
00607 osync_flag_set(entry->fl_dirty);
00608 osync_flag_unset(entry->fl_synced);
00609 send_mappingentry_changed(engine, entry);
00610
00611 osync_flag_set(mapping->fl_solved);
00612 send_mapping_changed(engine, mapping);
00613 osync_trace(TRACE_EXIT, "%s", __func__);
00614 }
00615