<commit_before>/*
 * libosengine - A synchronization engine for the opensync framework
 * Copyright (C) 2004-2005  <NAME> <<EMAIL>>
 * Copyright (C) 2007       <NAME> <<EMAIL>>
 * 
 * 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 "opensync.h"
#include "opensync_internals.h"

#include "opensync-archive.h"
#include "opensync-group.h"
#include "opensync-engine.h"
#include "opensync-client.h"
#include "opensync-data.h"
#include "opensync-mapping.h"
#include "opensync-plugin.h"

#include "opensync_obj_engine.h"
#include "opensync_obj_engine_internals.h"

#include "opensync_sink_engine_internals.h"
#include "opensync_mapping_entry_engine_internals.h"

#include "opensync_mapping_engine.h"
#include "opensync_mapping_engine_internals.h"

OSyncMappingEngine *osync_mapping_engine_new(OSyncObjEngine *parent, OSyncMapping *mapping, OSyncError **error)
{
	osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parent, mapping, error);

	osync_assert(parent);
	osync_assert(mapping);
	
	OSyncMappingEngine *engine = osync_try_malloc0(sizeof(OSyncMappingEngine), error);
	if (!engine)
		goto error;
	engine->ref_count = 1;
	
	engine->mapping = mapping;
	osync_mapping_ref(mapping);
	
	engine->parent = parent;
	engine->synced = TRUE;
	
	GList *s = NULL;
	for (s = parent->sink_engines; s; s = s->next) {
		OSyncSinkEngine *sink_engine = s->data;
		
		OSyncMember *member = osync_client_proxy_get_member(sink_engine->proxy);
		OSyncMappingEntry *mapping_entry = osync_mapping_find_entry_by_member_id(mapping, osync_member_get_id(member));
		osync_assert(mapping_entry);
		
		OSyncMappingEntryEngine *entry_engine = osync_entry_engine_new(mapping_entry, engine, sink_engine, parent, error);
		if (!entry_engine)
			goto error_free_engine;

		engine->entries = g_list_append(engine->entries, entry_engine);
	}
	
	osync_trace(TRACE_EXIT, "%s: %p", __func__, engine);
	return engine;

error_free_engine:
	osync_mapping_engine_unref(engine);
error:
	osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
	return NULL;
}

OSyncMappingEngine *osync_mapping_engine_ref(OSyncMappingEngine *engine)
{
	osync_assert(engine);
	
	g_atomic_int_inc(&(engine->ref_count));

	return engine;
}

void osync_mapping_engine_unref(OSyncMappingEngine *engine)
{
	osync_assert(engine);
		
	if (g_atomic_int_dec_and_test(&(engine->ref_count))) {
		if (engine->mapping)
			osync_mapping_unref(engine->mapping);
		
		if (engine->master)
			osync_entry_engine_unref(engine->master);
		
		while (engine->entries) {
			OSyncMappingEntryEngine *entry = engine->entries->data;
			osync_entry_engine_unref(entry);
			
			engine->entries = g_list_remove(engine->entries, engine->entries->data);
		}
		
		g_free(engine);
	}
}

static OSyncMappingEntryEngine *_osync_mapping_engine_find_entry(OSyncMappingEngine *engine, OSyncChange *change)
{
	GList *e;
	for (e = engine->entries; e; e = e->next) {
		OSyncMappingEntryEngine *entry = e->data;
		if (change && entry->change == change)
			return entry;
	}
	
	return NULL;
}

OSyncMember *osync_mapping_engine_change_find_member(OSyncMappingEngine *engine, OSyncChange *change)
{
	osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, engine, change);

	OSyncMember *member = NULL;
	OSyncMappingEntryEngine *entry = _osync_mapping_engine_find_entry(engine, change);

	if (!entry)
		goto end;

	member = osync_client_proxy_get_member(entry->sink_engine->proxy);

end:	
	osync_trace(TRACE_EXIT, "%s: %p", __func__, member);
	return member;
}

static OSyncMappingEntryEngine *_osync_mapping_engine_get_latest_entry(OSyncMappingEngine *engine, OSyncError **error)
{
	osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, engine, error);

	OSyncMappingEntryEngine *latest_entry = NULL; 
	OSyncChange *latest_change = NULL;
	time_t latest = 0;
	int i;

	osync_trace(TRACE_INTERNAL, "mapping number: %i", osync_mapping_engine_num_changes(engine));
	for (i=0; i < osync_mapping_engine_num_changes(engine); i++) {
		OSyncChange *change = osync_mapping_engine_nth_change(engine, i); 

		if (osync_change_get_changetype(change) == OSYNC_CHANGE_TYPE_UNKNOWN)
			continue;

		OSyncData *data = osync_change_get_data(change);

		if (!osync_data_has_data(data))
			continue;

		time_t cur = osync_data_get_revision(data, error);

		if (cur < 0)
			goto error;

		if (cur == latest) {
			osync_error_set(error, OSYNC_ERROR_GENERIC, "Entries got changed at the same time. Can't decide.");
			goto error;
		}

		if (cur < latest)
			continue;

		latest = cur;
		latest_change = change;
	}

	if (!latest_change) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Can't find the latest change.");
		goto error;
	}

	latest_entry = _osync_mapping_engine_find_entry(engine, latest_change);

	if (!latest_entry) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Can't find the latest entry.");
		goto error;
	}

	osync_trace(TRACE_EXIT, "%s: %p", __func__, latest_entry);
	return latest_entry;

error:
	osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
	return NULL;
}

osync_bool osync_mapping_engine_supports_ignore(OSyncMappingEngine *engine)
{
	osync_trace(TRACE_ENTRY, "%s(%p)", __func__, engine);
	osync_assert(engine);

	OSyncObjEngine *parent = engine->parent;

	osync_bool ignore_supported = TRUE;

	GList *s = NULL;
	for (s = parent->sink_engines; s; s = s->next) {
		OSyncSinkEngine *sink_engine = s->data;<commit_msg>Don't use TRACE_EXIT when not latest revision can be determined. fixes #882<commit_after>/*
 * libosengine - A synchronization engine for the opensync framework
 * Copyright (C) 2004-2005  <NAME> <<EMAIL>>
 * Copyright (C) 2007       <NAME> <<EMAIL>>
 * 
 * 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 "opensync.h"
#include "opensync_internals.h"

#include "opensync-archive.h"
#include "opensync-group.h"
#include "opensync-engine.h"
#include "opensync-client.h"
#include "opensync-data.h"
#include "opensync-mapping.h"
#include "opensync-plugin.h"

#include "opensync_obj_engine.h"
#include "opensync_obj_engine_internals.h"

#include "opensync_sink_engine_internals.h"
#include "opensync_mapping_entry_engine_internals.h"

#include "opensync_mapping_engine.h"
#include "opensync_mapping_engine_internals.h"

OSyncMappingEngine *osync_mapping_engine_new(OSyncObjEngine *parent, OSyncMapping *mapping, OSyncError **error)
{
	osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parent, mapping, error);

	osync_assert(parent);
	osync_assert(mapping);
	
	OSyncMappingEngine *engine = osync_try_malloc0(sizeof(OSyncMappingEngine), error);
	if (!engine)
		goto error;
	engine->ref_count = 1;
	
	engine->mapping = mapping;
	osync_mapping_ref(mapping);
	
	engine->parent = parent;
	engine->synced = TRUE;
	
	GList *s = NULL;
	for (s = parent->sink_engines; s; s = s->next) {
		OSyncSinkEngine *sink_engine = s->data;
		
		OSyncMember *member = osync_client_proxy_get_member(sink_engine->proxy);
		OSyncMappingEntry *mapping_entry = osync_mapping_find_entry_by_member_id(mapping, osync_member_get_id(member));
		osync_assert(mapping_entry);
		
		OSyncMappingEntryEngine *entry_engine = osync_entry_engine_new(mapping_entry, engine, sink_engine, parent, error);
		if (!entry_engine)
			goto error_free_engine;

		engine->entries = g_list_append(engine->entries, entry_engine);
	}
	
	osync_trace(TRACE_EXIT, "%s: %p", __func__, engine);
	return engine;

error_free_engine:
	osync_mapping_engine_unref(engine);
error:
	osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
	return NULL;
}

OSyncMappingEngine *osync_mapping_engine_ref(OSyncMappingEngine *engine)
{
	osync_assert(engine);
	
	g_atomic_int_inc(&(engine->ref_count));

	return engine;
}

void osync_mapping_engine_unref(OSyncMappingEngine *engine)
{
	osync_assert(engine);
		
	if (g_atomic_int_dec_and_test(&(engine->ref_count))) {
		if (engine->mapping)
			osync_mapping_unref(engine->mapping);
		
		if (engine->master)
			osync_entry_engine_unref(engine->master);
		
		while (engine->entries) {
			OSyncMappingEntryEngine *entry = engine->entries->data;
			osync_entry_engine_unref(entry);
			
			engine->entries = g_list_remove(engine->entries, engine->entries->data);
		}
		
		g_free(engine);
	}
}

static OSyncMappingEntryEngine *_osync_mapping_engine_find_entry(OSyncMappingEngine *engine, OSyncChange *change)
{
	GList *e;
	for (e = engine->entries; e; e = e->next) {
		OSyncMappingEntryEngine *entry = e->data;
		if (change && entry->change == change)
			return entry;
	}
	
	return NULL;
}

OSyncMember *osync_mapping_engine_change_find_member(OSyncMappingEngine *engine, OSyncChange *change)
{
	osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, engine, change);

	OSyncMember *member = NULL;
	OSyncMappingEntryEngine *entry = _osync_mapping_engine_find_entry(engine, change);

	if (!entry)
		goto end;

	member = osync_client_proxy_get_member(entry->sink_engine->proxy);

end:	
	osync_trace(TRACE_EXIT, "%s: %p", __func__, member);
	return member;
}

static OSyncMappingEntryEngine *_osync_mapping_engine_get_latest_entry(OSyncMappingEngine *engine, OSyncError **error)
{
	osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, engine, error);

	OSyncMappingEntryEngine *latest_entry = NULL; 
	OSyncChange *latest_change = NULL;
	time_t latest = 0;
	int i;

	osync_trace(TRACE_INTERNAL, "mapping number: %i", osync_mapping_engine_num_changes(engine));
	for (i=0; i < osync_mapping_engine_num_changes(engine); i++) {
		OSyncChange *change = osync_mapping_engine_nth_change(engine, i); 

		if (osync_change_get_changetype(change) == OSYNC_CHANGE_TYPE_UNKNOWN)
			continue;

		OSyncData *data = osync_change_get_data(change);

		if (!osync_data_has_data(data))
			continue;

		time_t cur = osync_data_get_revision(data, error);

		if (cur < 0)
			goto error;
		
		/* If there are several changes/entries having the
		   same _and_ the latest revision -> don't declare
		   a latest_change. Since it's not guranteed that those are
		   equal, even with the _same_ revision.
		 */
		if (cur == latest)
			latest_change = NULL;

		if (cur <= latest)
			continue;

		latest = cur;
		latest_change = change;
	}

	if (!latest_change) {
		osync_trace(TRACE_EXIT, "%s: Can't find the latest change.",
				__func__);
		return NULL;
	}

	latest_entry = _osync_mapping_engine_find_entry(engine, latest_change);

	if (!latest_entry) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Can't find the latest entry of the latest change.");
		goto error;
	}

	osync_trace(TRACE_EXIT, "%s: %p", __func__, latest_entry);
	return latest_entry;

error:
	osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
	return NULL;
}

osync_bool osync_mapping_engine_supports_ignore(OSyncMappingEngine *engine)
{
	osync_trace(TRACE_ENTRY, "%s(%p)", __func__, engine);
	osync_assert(engine);

	OSyncObjEngine *parent = engine->parent;

	osync_bool ignore_supported = TRUE;

	GList *s = NULL;
	for (s = parent->sink_engines; s; s = s->next) {
		OSyncSinkEngine *sink_engine = s->data;
{'fraction_non_alphanumeric': 0.1126268777913114, 'fraction_numerical': 0.005602923264311815, 'mean_word_length': 5.506075013206551, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 82, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '239604', 'n_tokens_mistral': 4509, 'n_tokens_neox': 4212, 'n_words': 997}