Commit 2d2c38f9 authored by Aurel's avatar Aurel

implement better deletion mecanism & remove workflow transition overhead

parent 1b4cd9c7
......@@ -78,7 +78,10 @@ class SyncMLAsynchronousEngine(EngineMixin):
syncml_response = self._generateBaseResponse(subscription)
syncml_response.addFinal()
else:
self.runGetAndActivate(subscription=subscription, tag=tag)
# Make sure it is launched after indexation step
self.runGetAndActivate(subscription=subscription, tag=tag,
after_method_id=("getAndIndex",
"SQLCatalog_indexSyncMLSignatureList"))
syncml_logger.info("X-> Client is sendind modification in activities")
# As we generated all activities to send data at once, process must not
# go back here, go into processing state thus status will be applied and
......@@ -163,10 +166,10 @@ class SyncMLAsynchronousEngine(EngineMixin):
# Apply command & send modifications
# Apply status about object send & synchronized if any
sync_status_counter = self._readStatusList(syncml_request, subscriber,
self._readStatusList(syncml_request, subscriber,
generate_alert=True)
syncml_response = None
tag = subscription_path = subscriber.getRelativeUrl()
tag = subscriber.getRelativeUrl()
after_method_id = None
if subscriber.getSynchronizationState() == "sending_modifications":
if syncml_request.isFinal:
......@@ -202,15 +205,13 @@ class SyncMLAsynchronousEngine(EngineMixin):
if syncml_request.isFinal:
# Server then sends its modifications
subscriber.sendModifications()
# Now that everything is ok, init sync information
if subscriber.getSyncmlAlertCode() not in ("one_way_from_client",
"refresh_from_client_only"):
# Reset signature only if we have to check modifications on server side
subscriber.initialiseSynchronization()
# Run indexation only once client have sent its modifications
subscriber.indexSourceData()
# Start to send modification only once we have processed
# all message from client
after_method_id='processServerSynchronization',
after_method_id=('processServerSynchronization',
'SQLCatalog_indexSyncMLDocumentList')
# XXX after tag might also be required to make sure all data are indexed
tag = (tag, "%s_reset" % subscriber.getPath(),)
# Do not continue in elif, as sending modifications is done in the same
# package as sending notifications
......@@ -242,10 +243,9 @@ class SyncMLAsynchronousEngine(EngineMixin):
after_tag=tag).sendMessage(
xml=str(syncml_response))
def runGetAndActivate(self, subscription, tag, after_method_id=None):
"""
Generate tag and method parameter and call the getAndActivate method
Launch the browsing of GID that will call the generation of syncml commands
"""
activate_kw = {
'activity' : 'SQLQueue',
......@@ -253,20 +253,16 @@ class SyncMLAsynchronousEngine(EngineMixin):
'tag' :tag,
'priority' :ACTIVITY_PRIORITY
}
method_kw = {
'subscription_path' : subscription.getRelativeUrl(),
}
pref = getSite().portal_preferences
subscription.getAndActivate(
callback="sendSyncCommand",
method_kw=method_kw,
activate_kw=activate_kw,
packet_size=pref.getPreferredDocumentRetrievedPerActivityCount(),
activity_count=pref.getPreferredRetrievalActivityCount(),
)
# Then get deleted document
# this will send also the final message of this sync part
subscription.activate(after_tag=tag)._getDeletedData()
# then send the final message of this sync part
subscription.activate(after_tag=tag,
priority=ACTIVITY_PRIORITY+1)._sendFinalMessage()
return True
......
......@@ -145,9 +145,10 @@ class EngineMixin(object):
signature = domain.getSignatureFromGid(object_gid)
if status['status_code'] == resolveSyncmlStatusCode('success'):
if signature:
domain.z_delete_data_from_path(path=signature.getPath())
domain._delObject(signature.getId())
else:
raise ValueError("Found no signature to delete")
raise ValueError("Found no signature to delete for gid %s" %(object_gid,))
else:
raise ValueError("Unknown status code : %r" % (status['status_code'],))
syncml_logger.error("\tObject deleted %s" %
......@@ -191,10 +192,8 @@ class EngineMixin(object):
if subscription.getAuthenticationState() != 'logged_in':
# Workflow action
subscription.login()
if subscription.getSyncmlAlertCode() not in ("one_way_from_server",
"refresh_from_server_only"):
# Reset signature only if client send its modification to server
subscription.initialiseSynchronization()
subscription.indexSourceData(client=True)
# Create the package 1
syncml_response = SyncMLResponse()
......@@ -301,7 +300,9 @@ class EngineMixin(object):
'one_way_from_server',
'refresh_from_client_only',
'one_way_from_client'):
# XXX Why re-editing here ?
# Make sure we update configuration based on publication data
# so that manual edition is propagated
# XXX Must check all properties that must be setted
subscriber.setXmlBindingGeneratorMethodId(
publication.getXmlBindingGeneratorMethodId())
subscriber.setConduitModuleId(publication.getConduitModuleId())
......
......@@ -29,6 +29,7 @@ from logging import getLogger
from Products.ERP5SyncML.Engine.EngineMixin import EngineMixin
from Products.ERP5SyncML.SyncMLConstant import SynchronizationError
from Products.ERP5.ERP5Site import getSite
syncml_logger = getLogger('ERP5SyncML')
......@@ -81,13 +82,12 @@ class SyncMLSynchronousEngine(EngineMixin):
# We only get data from server
finished = True
else:
finished = subscription._getSyncMLData(
syncml_response=syncml_response,
)
finished = subscription._getSyncMLData(syncml_response=syncml_response,
min_gid=None, max_gid=None)
syncml_logger.info("-> Client sendind modification, finished %s" % (finished,))
if finished:
# Add deleted objets
subscription._getDeletedData(syncml_response=syncml_response)
#subscription._getDeletedData(syncml_response=syncml_response)
# Notify that all modifications were sent
syncml_response.addFinal()
# Will then start processing sync commands from server
......@@ -191,10 +191,8 @@ class SyncMLSynchronousEngine(EngineMixin):
if syncml_request.isFinal:
# Server will now send its modifications
subscriber.sendModifications()
if subscriber.getSyncmlAlertCode() not in ("one_way_from_client",
"refresh_from_client_only"):
# Reset signature only if we have to check modifications on server side
subscriber.initialiseSynchronization()
# Run indexation only once client has sent its modifications
subscriber.indexSourceData()
# Do not continue in elif, as sending modifications is done in the same
# package as sending notifications
......@@ -205,11 +203,11 @@ class SyncMLSynchronousEngine(EngineMixin):
# We only get data from client
finished = True
else:
finished = subscriber._getSyncMLData(
syncml_response=syncml_response)
finished = subscriber._getSyncMLData(syncml_response=syncml_response,
min_gid=None, max_gid=None)
syncml_logger.info("-> Server sendind data, finished %s" % (finished,))
if finished:
subscriber._getDeletedData(syncml_response=syncml_response)
#subscriber._getDeletedData(syncml_response=syncml_response)
syncml_response.addFinal()
subscriber.waitNotifications()
# Do not go into finished here as we must wait for
......
......@@ -399,13 +399,14 @@ class SynchronizationTool(BaseTool):
return str(syncml_response)
# As engines are not zodb objects, the tool acts as a placeholder for methods
# that need to be called in activities
def applySyncCommand(self, subscription_path, response_message_id,
activate_kw, **kw):
"""
This methods is intented to be called by asynchronous engine in activity to
apply sync commands for a subset of data
As engines are not zodb object, the tool acts as a placeholder for method
that need to be called in activities
"""
subscription = self.restrictedTraverse(subscription_path)
assert subscription is not None, "Impossible to find subscription %s" \
......@@ -437,13 +438,11 @@ class SynchronizationTool(BaseTool):
def sendSyncCommand(self, id_list, message_id, subscription_path,
activate_kw, is_final_message=False):
def sendSyncCommand(self, gid_list, message_id, subscription_path,
activate_kw, first_call=False, last_call=False):
"""
This methods is intented to be called by asynchronous engine in activity to
send sync commands for a subset of data
As engines are not zodb object, the tool acts as a placeholder for method
that need to be called in activities
"""
subscription = self.restrictedTraverse(subscription_path)
assert subscription is not None, "Impossible to find subscription %s" \
......@@ -457,17 +456,14 @@ class SynchronizationTool(BaseTool):
source=subscription.getSubscriptionUrlString())
syncml_response.addBody()
subscription._getSyncMLData(
syncml_response=syncml_response,
id_list=id_list,
gid_list=gid_list,
first_call=first_call,
last_call=last_call,
)
if is_final_message:
# Notify that all modifications were sent
syncml_response.addFinal()
# Send the message in activity to prevent recomputing data in case of
# Send the message in activity to prevent recomputation of data in case of
# transport failure
# activate_kw["group_method_id"] = None
# activate_kw["group_method_cost"] = .05
......
......@@ -44,6 +44,7 @@ from Products.ERP5SyncML.Document import SyncMLSubscription
from Products.ERP5SyncML.tests.testERP5SyncMLMixin import TestERP5SyncMLMixin \
as TestMixin
from Products.ERP5Type.tests.backportUnittest import expectedFailure
from _mysql_exceptions import OperationalError
class TestERP5SyncMLMixin(TestMixin):
......@@ -98,6 +99,8 @@ class TestERP5SyncMLMixin(TestMixin):
def afterSetUp(self):
"""Setup."""
self.login()
self.portal.z_drop_syncml()
self.portal.z_create_syncml()
# This test creates Person inside Person, so we modifiy type information to
# allow anything inside Person (we'll cleanup on teardown)
self.getTypesTool().getTypeInfo('Person').filter_content_types = 0
......@@ -228,6 +231,7 @@ class TestERP5SyncMLMixin(TestMixin):
result = portal_sync.processClientSynchronization(subscription.getPath())
self.tic()
nb_message += 1
self.tic()
return nb_message
def synchronizeWithBrokenMessage(self, id):
......@@ -948,6 +952,8 @@ return [context[%r]]
person_server.manage_delObjects(self.id1)
person_client1 = self.getPersonClient1()
person_client1.manage_delObjects(self.id2)
# import ipdb
# ipdb.set_trace()
self.synchronize(self.sub_id1)
self.synchronize(self.sub_id2)
self.checkSynchronizationStateIsSynchronized()
......@@ -1543,7 +1549,7 @@ return [context[%r]]
self.assertEquals(client_person.getLastName(), self.last_name1)
# reset for refresh sync
# after synchronize, the client object retrieve value of server
# after synchronization, the client retrieves value from server
self.resetSignaturePublicationAndSubscription()
self.synchronize(self.sub_id1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment