You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

638 lines
20 KiB

/*
* libopensync - A synchronization framework
* Copyright (C) 2004-2005 Armin Bauer <armin.bauer@opensync.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "engine.h"
#include "engine_internals.h"
/**
* @defgroup OSEngineMappingPrivate OpenSync Mapping Internals
* @ingroup OSEnginePrivate
* @brief The internals the mappings
*
*/
/*@{*/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
OSyncMappingTable *osengine_mappingtable_new(OSyncEngine *engine)
{
osync_trace(TRACE_ENTRY, "osengine_mappingtable_new(%p)", engine);
OSyncMappingTable *table = g_malloc0(sizeof(OSyncMappingTable));
table->engine = engine;
table->group = engine->group;
GList *c;
for (c = engine->clients; c; c = c->next) {
OSyncClient *client = c->data;
osengine_mappingview_new(table, client);
}
osync_trace(TRACE_EXIT, "osengine_mappingtable_new: %p", table);
return table;
}
void osengine_mappingtable_reset(OSyncMappingTable *table)
{
GList *v;
for (v = table->views; v; v = v->next) {
OSyncMappingView *view = v->data;
osengine_mappingview_reset(view);
}
}
void osengine_mappingtable_free(OSyncMappingTable *table)
{
osync_trace(TRACE_ENTRY, "osengine_mappingtable_free(%p)", table);
GList *c = NULL;
GList *m = NULL;
GList *mappings = g_list_copy(table->mappings);
GList *unmapped = g_list_copy(table->unmapped);
GList *views = g_list_copy(table->views);
osync_trace(TRACE_INTERNAL, "Free mappings");
for (m = mappings; m; m = m->next) {
OSyncMapping *mapping = m->data;
osengine_mapping_free(mapping);
}
osync_trace(TRACE_INTERNAL, "Free unmapped");
for (c = unmapped; c; c = c->next) {
OSyncMappingEntry *entry = c->data;
osengine_mappingentry_free(entry);
}
for (c = views; c; c = c->next) {
OSyncMappingView *view = c->data;
osengine_mappingview_free(view);
}
g_list_free(mappings);
g_list_free(unmapped);
g_list_free(views);
g_free(table);
osync_trace(TRACE_EXIT, "osengine_mappingtable_free");
}
OSyncMappingEntry *osengine_mappingtable_find_entry(OSyncMappingTable *table, const char *uid, const char *objtype, long long int memberid)
{
osync_trace(TRACE_ENTRY, "%s(%p, %s, %s)", __func__, table, uid, objtype ? objtype : "None");
GList *v;
int count_of_entries = 0; /*must not be more the one for objtype=NULL*/
OSyncMappingEntry *ret_entry = NULL;
for (v = table->views; v; v = v->next) {
OSyncMappingView *view = v->data;
GList *c;
if (memberid && memberid != osync_member_get_id(view->client->member))
continue;
for (c = view->changes; c; c = c->next) {
OSyncMappingEntry *entry = c->data;
g_assert(entry->change);
if(objtype){
if ( (!strcmp(
osync_change_get_uid(entry->change), uid)) &&
(!strcmp(
osync_objtype_get_name(
osync_change_get_objtype(entry->change))
, objtype))
) {
ret_entry = entry;
count_of_entries++;
}
} else { /**objtype is NULL ... try to find a entry based on uid*/
if (!strcmp(osync_change_get_uid(entry->change), uid)) {
ret_entry = entry;
count_of_entries++;
}
}
}
}
if(count_of_entries == 1 && ret_entry){
osync_trace(TRACE_EXIT, "%s: %p", __func__, ret_entry);
return ret_entry;
}
if(count_of_entries >1){
if (!objtype)
{
osync_trace(TRACE_EXIT_ERROR, "%s: possible dataloss", __func__ );
} else {
osync_trace(TRACE_EXIT_ERROR, "%s: changes.db corrupted", __func__ );
}
return NULL;
}
osync_trace(TRACE_EXIT, "%s: Not Found", __func__);
return NULL;
}
OSyncMappingEntry *osengine_mappingtable_store_change(OSyncMappingTable *table, OSyncChange *change)
{
osync_trace(TRACE_ENTRY, "osengine_mappingtable_store_change(%p, %p)", table, change);
OSyncMappingView *view = osengine_mappingtable_find_view(table, osync_change_get_member(change));
g_assert(view);
OSyncMappingEntry *entry = osengine_mappingview_store_change(view, change);
osync_trace(TRACE_EXIT, "osengine_mappingtable_store_change: %p", entry);
return entry;
}
OSyncMapping *osengine_mappingtable_find_mapping(OSyncMappingTable *table, OSyncChange *change)
{
GList *m;
for (m = table->mappings; m; m = m->next) {
OSyncMapping *mapping = m->data;
if (osengine_mapping_find_entry(mapping, change, NULL))
return mapping;
}
return NULL;
}
OSyncMapping *osengine_mappingtable_mapping_from_id(OSyncMappingTable *table, long long int id)
{
GList *m;
for (m = table->mappings; m; m = m->next) {
OSyncMapping *mapping = m->data;
if (mapping->id == id)
return mapping;
}
return NULL;
}
OSyncMappingView *osengine_mappingtable_find_view(OSyncMappingTable *table, OSyncMember *member)
{
GList *v;
for (v = table->views; v; v = v->next) {
OSyncMappingView *view = v->data;
if (view->memberid == osync_member_get_id(member))
return view;
}
return NULL;
}
void osengine_mappingtable_add_mapping(OSyncMappingTable *table, OSyncMapping *mapping)
{
table->mappings = g_list_append(table->mappings, mapping);
mapping->table = table;
}
osync_bool osengine_mappingtable_load(OSyncMappingTable *table, OSyncError **error)
{
osync_trace(TRACE_ENTRY, "osengine_mappingtable_load(%p, %p)", table, error);
OSyncChange **changes = NULL;
if (!osync_changes_load(table->group, &changes, error)) {
osync_trace(TRACE_EXIT_ERROR, "osengine_mappingtable_load: %s", osync_error_print(error));
return FALSE;
}
int i = 0;
OSyncChange *change = NULL;
OSyncMapping *mapping = NULL;
while ((change = changes[i])) {
OSyncMappingEntry *entry = osengine_mappingentry_new(NULL);
entry->change = change;
//entry->orig_change = change;
entry->client = (OSyncClient *)osync_member_get_data(osync_change_get_member(change));
if (!osync_change_get_mappingid(change)) {
table->unmapped = g_list_append(table->unmapped, entry);
} else {
if (!mapping || mapping->id != osync_change_get_mappingid(change)) {
mapping = osengine_mapping_new(table);
mapping->id = osync_change_get_mappingid(change);
}
osengine_mapping_add_entry(mapping, entry);
}
osync_flag_set(entry->fl_has_data);
OSyncMappingView *view = osengine_mappingtable_find_view(table, osync_change_get_member(change));
if (view)
osengine_mappingview_add_entry(view, entry);
i++;
}
osync_trace(TRACE_EXIT, "osengine_mappingtable_load: TRUE");
return TRUE;
}
long long int osengine_mappingtable_get_next_id(OSyncMappingTable *table)
{
long long int new_id = 1;
GList *m;
for (m = table->mappings; m; m = m->next) {
OSyncMapping *mapping = m->data;
if (new_id <= mapping->id)
new_id = mapping->id + 1;
}
return new_id;
}
void osengine_mappingtable_inject_changes(OSyncMappingTable *table)
{
osync_trace(TRACE_ENTRY, "%s(%p)", __func__, table);
//OSyncEngine *engine = table->engine;
char **uids = NULL;
char **objtypes = NULL;
long long int *memberids = NULL;
int *types = NULL;
char *uid = NULL;
char *objtype = NULL;
int type = 0;
int i = 0;
OSyncError *error = NULL;
osync_group_open_changelog(table->engine->group, &uids, &objtypes, &memberids, &types, &error);
for (i = 0; (uid = uids[i]) ; i++) {
type = types[i];
objtype = objtypes[i];
long long int memberid = memberids[i];
OSyncMappingEntry *entry = osengine_mappingtable_find_entry(table, uid, objtype, memberid);
if (!entry) {
osync_trace(TRACE_INTERNAL, "Mappingtable and changelog inconsistent: no entry with uid %s", uid);
/*FIXME: We should be able to return error here. What if entry == NULL? */
g_assert_not_reached();
}
osync_change_set_changetype(entry->change, type);
osync_trace(TRACE_INTERNAL, "Injecting %p with changetype %i", entry, osync_change_get_changetype(entry->change));
osync_flag_attach(entry->fl_read, table->engine->cmb_read_all);
/* Set fl_mapped accordingly, if the entry was already mapped previously */
if (entry->mapping)
osync_flag_set(entry->fl_mapped);
//send_read_change(engine, entry);
}
osync_trace(TRACE_EXIT, "%s", __func__);
}
OSyncMappingTable *_osengine_mappingtable_load_group(OSyncGroup *group)
{
OSyncMappingTable *table = g_malloc0(sizeof(OSyncMappingTable));
table->group = group;
int i;
for (i = 0; i < osync_group_num_members(group); i++) {
OSyncMember *member = osync_group_nth_member(group, i);
OSyncMappingView *view = g_malloc0(sizeof(OSyncMappingView));
table->views = g_list_append(table->views, view);
view->table = table;
view->memberid = osync_member_get_id(member);
}
if (!osengine_mappingtable_load(table, NULL))
return NULL;
return table;
}
void osengine_mappingtable_close(OSyncMappingTable *table)
{
osync_changes_close(table->group);
//FIXME Free the changes on the views
}
OSyncMapping *osengine_mapping_new(OSyncMappingTable *table)
{
g_assert(table);
OSyncMapping *mapping = g_malloc0(sizeof(OSyncMapping));
osengine_mappingtable_add_mapping(table, mapping);
if (table->engine) {
mapping->fl_solved = osync_flag_new(NULL);
mapping->fl_chkconflict = osync_flag_new(NULL);
osync_flag_set(mapping->fl_chkconflict);
mapping->fl_multiplied = osync_flag_new(NULL);
osync_flag_set(mapping->fl_multiplied);
mapping->cmb_has_data = osync_comb_flag_new(FALSE, FALSE);
osync_flag_set_pos_trigger(mapping->cmb_has_data, (OSyncFlagTriggerFunc)send_mapping_changed, table->engine, mapping);
mapping->cmb_has_info = osync_comb_flag_new(FALSE, FALSE);
mapping->cmb_synced = osync_comb_flag_new(FALSE, TRUE);
mapping->cmb_deleted = osync_comb_flag_new(FALSE, FALSE);
osync_flag_attach(mapping->cmb_synced, table->engine->cmb_synced);
osync_flag_attach(mapping->fl_multiplied, table->engine->cmb_multiplied);
osync_flag_attach(mapping->fl_chkconflict, table->engine->cmb_chkconflict);
}
osync_trace(TRACE_INTERNAL, "osengine_mapping_new(%p): %p", table, mapping);
return mapping;
}
void osengine_mapping_free(OSyncMapping *mapping)
{
osync_trace(TRACE_ENTRY, "osengine_mapping_free(%p)", mapping);
while (g_list_nth_data(mapping->entries, 0))
osengine_mappingentry_free(g_list_nth_data(mapping->entries, 0));
osync_flag_detach(mapping->cmb_synced);
osync_flag_detach(mapping->fl_chkconflict);
osync_flag_detach(mapping->fl_multiplied);
mapping->table->mappings = g_list_remove(mapping->table->mappings, mapping);
osync_flag_free(mapping->fl_solved);
osync_flag_free(mapping->cmb_has_data);
osync_flag_free(mapping->cmb_has_info);
osync_flag_free(mapping->cmb_synced);
osync_flag_free(mapping->fl_chkconflict);
osync_flag_free(mapping->cmb_deleted);
osync_flag_free(mapping->fl_multiplied);
g_free(mapping);
osync_trace(TRACE_EXIT, "osengine_mapping_free");
}
void osengine_mapping_add_entry(OSyncMapping *mapping, OSyncMappingEntry *entry)
{
osync_trace(TRACE_INTERNAL, "osengine_mapping_add_entry(%p, %p)", mapping, entry);
g_assert(!osengine_mapping_find_entry(mapping, NULL, entry->view));
mapping->entries = g_list_append(mapping->entries, entry);
entry->mapping = mapping;
if (mapping->table->engine) {
osync_flag_attach(entry->fl_has_data, mapping->cmb_has_data);
osync_flag_attach(entry->fl_has_info, mapping->cmb_has_info);
osync_flag_attach(entry->fl_synced, mapping->cmb_synced);
osync_flag_attach(entry->fl_deleted, mapping->cmb_deleted);
osync_flag_set_pos_trigger(entry->fl_dirty, (OSyncFlagTriggerFunc)send_mappingentry_changed, mapping->table->engine, entry);
}
osync_change_set_mappingid(entry->change, mapping->id);
mapping->table->unmapped = g_list_remove(mapping->table->unmapped, entry);
mapping->table->entries = g_list_append(mapping->table->entries, entry);
}
void osengine_mapping_remove_entry(OSyncMapping *mapping, OSyncMappingEntry *entry)
{
mapping->entries = g_list_remove(mapping->entries, entry);
mapping->table->entries = g_list_remove(mapping->table->entries, entry);
entry->mapping = NULL;
osync_flag_detach(entry->fl_has_data);
osync_flag_detach(entry->fl_has_info);
osync_flag_detach(entry->fl_synced);
osync_flag_detach(entry->fl_deleted);
}
OSyncMappingEntry *osengine_mapping_find_entry(OSyncMapping *mapping, OSyncChange *change, OSyncMappingView *view)
{
GList *e;
for (e = mapping->entries; e; e = e->next) {
OSyncMappingEntry *entry = e->data;
if (change && entry->change == change)
return entry;
if (view && entry->view == view)
return entry;
}
return NULL;
}
OSyncMappingEntry *osengine_mapping_nth_entry(OSyncMapping *mapping, int nth)
{
return (OSyncMappingEntry *)g_list_nth_data(mapping->entries, nth);
}
int osengine_mapping_num_changes(OSyncMapping *mapping)
{
return g_list_length(mapping->entries);
}
OSyncChange *osengine_mapping_nth_change(OSyncMapping *mapping, int nth)
{
OSyncMappingEntry *entry = g_list_nth_data(mapping->entries, nth);
if (!entry)
return NULL;
return entry->change;
}
long long osengine_mapping_get_id(OSyncMapping *mapping)
{
return mapping->id;
}
void osengine_mapping_reset(OSyncMapping *mapping)
{
osync_trace(TRACE_ENTRY, "osengine_mapping_reset(%p)", mapping);
GList *e;
for (e = mapping->entries; e; e = e->next) {
OSyncMappingEntry *entry = e->data;
osengine_mappingentry_reset(entry);
}
osync_flag_set(mapping->fl_multiplied);
osync_flag_set(mapping->fl_chkconflict);
mapping->master = NULL;
osync_trace(TRACE_EXIT, "osengine_mapping_reset");
}
void osengine_mapping_delete(OSyncMapping *mapping)
{
osync_trace(TRACE_ENTRY, "osengine_mapping_delete(%p)", mapping);
GList *entries = g_list_copy(mapping->entries);
GList *c = NULL;
for (c = entries; c; c = c->next) {
OSyncMappingEntry *entry = c->data;
osync_change_delete(entry->change, NULL);
}
g_list_free(entries);
osengine_mapping_free(mapping);
osync_trace(TRACE_EXIT, "osengine_mapping_delete");
}
OSyncMappingView *osengine_mappingview_new(OSyncMappingTable *table, OSyncClient *client)
{
g_assert(table);
OSyncMappingView *view = g_malloc0(sizeof(OSyncMappingView));
table->views = g_list_append(table->views, view);
view->client = client;
view->table = table;
view->memberid = osync_member_get_id(client->member);
osync_trace(TRACE_INTERNAL, "osengine_mappingview_new(%p)", view);
return view;
}
void osengine_mappingview_free(OSyncMappingView *view)
{
osync_trace(TRACE_INTERNAL, "osengine_mappingview_free(%p)", view);
g_list_free(view->changes);
view->changes = NULL;
g_free(view);
}
void osengine_mappingview_add_entry(OSyncMappingView *view, OSyncMappingEntry *entry)
{
view->changes = g_list_append(view->changes, entry);
entry->view = view;
}
OSyncMappingEntry *osengine_mappingview_store_change(OSyncMappingView *view, OSyncChange *change)
{
osync_trace(TRACE_ENTRY, "osengine_mappingview_store_change(%p, %p)", view, change);
g_assert(change);
GList *c;
for (c = view->changes; c; c = c->next) {
OSyncMappingEntry *entry = c->data;
g_assert(entry->change);
/**
* not unique UID exception
* UID has to match and objtype has to match
**/
if (!strcmp(osync_change_get_uid(entry->change), osync_change_get_uid(change))) {
OSyncObjType * entry_objtype = osync_change_get_objtype(entry->change);
OSyncObjType * change_objtype = osync_change_get_objtype(change);
const char * entry_objtype_name = osync_objtype_get_name(entry_objtype);
const char * change_objtype_name = osync_objtype_get_name(change_objtype);
if (
(change_objtype_name == NULL) ||
(entry_objtype_name == NULL) ||
(!strcmp(change_objtype_name, entry_objtype_name)) ||
(!strcmp(change_objtype_name, "data")) ||
(!strcmp(entry_objtype_name, "data"))
) {
osengine_mappingentry_update(entry, change);
osync_trace(TRACE_EXIT, "osengine_mappingview_store_change: %p", entry);
return entry;
}
}
}
OSyncMappingEntry *newentry = osengine_mappingentry_new(NULL);
newentry->change = change;
newentry->client = view->client;
view->table->unmapped = g_list_append(view->table->unmapped, newentry);
osengine_mappingview_add_entry(view, newentry);
osync_trace(TRACE_EXIT, "osengine_mappingview_store_change: %p (New MappingEntry)", newentry);
return newentry;
}
osync_bool osengine_mappingview_uid_is_unique(OSyncMappingView *view, OSyncMappingEntry *entry, osync_bool spare_deleted)
{
GList *e = NULL;
for (e = view->changes; e; e = e->next) {
OSyncMappingEntry *exentry = e->data;
if ((exentry != entry) && (!spare_deleted || (osync_change_get_changetype(exentry->change) != CHANGE_DELETED)) && !strcmp(osync_change_get_uid(exentry->change), osync_change_get_uid(entry->change)))
return FALSE;
}
return TRUE;
}
void osengine_mappingview_reset(OSyncMappingView *view)
{
//g_list_free(view->changes);
//view->changes = NULL;
}
OSyncMappingEntry *osengine_mappingentry_new(OSyncMapping *mapping)
{
OSyncMappingEntry *entry = g_malloc0(sizeof(OSyncMappingEntry));
osync_trace(TRACE_INTERNAL, "osengine_mappingentry_new(%p): %p", mapping, entry);
entry->fl_has_data = osync_flag_new(NULL);
entry->fl_dirty = osync_flag_new(NULL);
entry->fl_mapped = osync_flag_new(NULL);
entry->fl_has_info = osync_flag_new(NULL);
entry->fl_synced = osync_flag_new(NULL);
entry->fl_deleted = osync_flag_new(NULL);
entry->fl_read = osync_flag_new(NULL);
entry->fl_committed = osync_flag_new(NULL);
osync_flag_set(entry->fl_synced);
if (mapping)
osengine_mapping_add_entry(mapping, entry);
return entry;
}
void osengine_mappingentry_free(OSyncMappingEntry *entry)
{
osync_trace(TRACE_INTERNAL, "osengine_mappingentry_free(%p)", entry);
if (entry->mapping)
osengine_mapping_remove_entry(entry->mapping, entry);
osync_flag_free(entry->fl_has_data);
osync_flag_free(entry->fl_dirty);
osync_flag_free(entry->fl_mapped);
osync_flag_free(entry->fl_has_info);
osync_flag_free(entry->fl_synced);
osync_flag_free(entry->fl_deleted);
osync_flag_free(entry->fl_read);
osync_flag_free(entry->fl_committed);
entry->view->changes = g_list_remove(entry->view->changes, entry);
entry->view = NULL;
g_free(entry);
}
void osengine_mappingentry_update(OSyncMappingEntry *entry, OSyncChange *change)
{
osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, entry, change);
OSyncObjFormat *format = osync_change_get_objformat(entry->change);
OSyncObjType *type = osync_change_get_objtype(entry->change);
osync_change_update(change, entry->change);
if (osync_change_get_changetype(change) == CHANGE_DELETED && format && type) {
osync_change_set_objformat(entry->change, format);
osync_change_set_objtype(entry->change, type);
osync_trace(TRACE_INTERNAL, "Change was deleted. Old objtype %s and format %s", osync_change_get_objtype(entry->change) ? osync_objtype_get_name(osync_change_get_objtype(entry->change)) : "None", osync_change_get_objformat(entry->change) ? osync_objformat_get_name(osync_change_get_objformat(entry->change)) : "None");
}
osync_trace(TRACE_EXIT, "%s", __func__);
}
OSyncMappingEntry *osengine_mappingentry_copy(OSyncMappingEntry *entry)
{
OSyncMappingEntry *newentry = osengine_mappingentry_new(NULL);
OSyncError *error = NULL;
newentry->change = osync_change_copy(entry->change, &error);
newentry->client = entry->client;
osengine_mappingview_add_entry(entry->view, newentry);
return newentry;
}
void osengine_mappingentry_reset(OSyncMappingEntry *entry)
{
osync_trace(TRACE_INTERNAL, "osengine_mappingentry_reset(%p)", entry);
osync_flag_set(entry->fl_has_data);
osync_flag_unset(entry->fl_dirty);
osync_flag_unset(entry->fl_has_info);
osync_flag_unset(entry->fl_deleted);
osync_flag_set(entry->fl_synced);
osync_change_reset(entry->change);
}
#endif
/** @} */