Fix bug with sync only using get

This commit is contained in:
Markus Unterwaditzer 2014-04-11 22:26:02 +02:00
parent be2f0851f3
commit afbbafdb69

View file

@ -22,27 +22,23 @@ import vdirsyncer.log
sync_logger = vdirsyncer.log.get('sync') sync_logger = vdirsyncer.log.get('sync')
def prepare_list(storage, href_to_uid): def prepare_list(storage, href_to_status):
download = []
for href, etag in storage.list(): for href, etag in storage.list():
props = {'etag': etag} props = {'etag': etag}
if href in href_to_uid: if href in href_to_status:
props['uid'] = href_to_uid[href] uid, old_etag = href_to_status[href]
props['uid'] = uid
if etag != old_etag:
download.append(href)
else: else:
item, new_etag = storage.get(href) download.append(href)
assert etag == new_etag
props['uid'] = item.uid
props['item'] = item
yield href, props yield href, props
if download:
def prefetch(storage, item_list, hrefs): for href, item, etag in storage.get_multi(download):
hrefs_to_prefetch = [] props = {'item': item, 'uid': item.uid, 'etag': etag}
for href in hrefs: yield href, props
if 'item' not in item_list[href]:
hrefs_to_prefetch.append(href)
for href, item, etag in storage.get_multi(hrefs_to_prefetch):
assert item_list[href]['etag'] == etag
item_list[href]['item'] = item
def sync(storage_a, storage_b, status, conflict_resolution=None): def sync(storage_a, storage_b, status, conflict_resolution=None):
@ -60,32 +56,28 @@ def sync(storage_a, storage_b, status, conflict_resolution=None):
provided, the sync function will raise provided, the sync function will raise
:py:exc:`vdirsyncer.exceptions.SyncConflict`. :py:exc:`vdirsyncer.exceptions.SyncConflict`.
''' '''
a_href_to_uid = dict( a_href_to_status = dict(
(href_a, uid) (href_a, (uid, etag_a))
for uid, (href_a, etag_a, href_b, etag_b) in status.iteritems() for uid, (href_a, etag_a, href_b, etag_b) in status.iteritems()
) )
b_href_to_uid = dict( b_href_to_status = dict(
(href_b, uid) (href_b, (uid, etag_b))
for uid, (href_a, etag_a, href_b, etag_b) in status.iteritems() for uid, (href_a, etag_a, href_b, etag_b) in status.iteritems()
) )
# href => {'etag': etag, 'item': optional item, 'uid': uid} # href => {'etag': etag, 'item': optional item, 'uid': uid}
list_a = dict(prepare_list(storage_a, a_href_to_uid)) list_a = dict(prepare_list(storage_a, a_href_to_status))
list_b = dict(prepare_list(storage_b, b_href_to_uid)) list_b = dict(prepare_list(storage_b, b_href_to_status))
a_uid_to_href = dict((x['uid'], href) for href, x in list_a.iteritems()) a_uid_to_href = dict((x['uid'], href) for href, x in list_a.iteritems())
b_uid_to_href = dict((x['uid'], href) for href, x in list_b.iteritems()) b_uid_to_href = dict((x['uid'], href) for href, x in list_b.iteritems())
del a_href_to_uid, b_href_to_uid del a_href_to_status, b_href_to_status
storages = { storages = {
'a': (storage_a, list_a, a_uid_to_href), 'a': (storage_a, list_a, a_uid_to_href),
'b': (storage_b, list_b, b_uid_to_href) 'b': (storage_b, list_b, b_uid_to_href)
} }
actions, prefetch_from_a, prefetch_from_b = \ actions = get_actions(storages, status)
get_actions(storages, status)
prefetch(storage_a, list_a, prefetch_from_a)
prefetch(storage_b, list_b, prefetch_from_b)
for action in actions: for action in actions:
action(storages, status, conflict_resolution) action(storages, status, conflict_resolution)
@ -180,8 +172,6 @@ def action_conflict_resolve(uid):
def get_actions(storages, status): def get_actions(storages, status):
prefetch_from_a = []
prefetch_from_b = []
actions = [] actions = []
storage_a, list_a, a_uid_to_href = storages['a'] storage_a, list_a, a_uid_to_href = storages['a']
@ -203,23 +193,17 @@ def get_actions(storages, status):
if a and b: # missing status if a and b: # missing status
actions.append(action_conflict_resolve(uid)) actions.append(action_conflict_resolve(uid))
elif a and not b: # new item was created in a elif a and not b: # new item was created in a
prefetch_from_a.append(href_a)
actions.append(action_upload(uid, 'a', 'b')) actions.append(action_upload(uid, 'a', 'b'))
elif not a and b: # new item was created in b elif not a and b: # new item was created in b
prefetch_from_b.append(href_b)
actions.append(action_upload(uid, 'b', 'a')) actions.append(action_upload(uid, 'b', 'a'))
else: else:
_, status_etag_a, _, status_etag_b = status[uid] _, status_etag_a, _, status_etag_b = status[uid]
if a and b: if a and b:
if a['etag'] != status_etag_a and b['etag'] != status_etag_b: if a['etag'] != status_etag_a and b['etag'] != status_etag_b:
prefetch_from_a.append(href_a)
prefetch_from_b.append(href_b)
actions.append(action_conflict_resolve(uid)) actions.append(action_conflict_resolve(uid))
elif a['etag'] != status_etag_a: # item was updated in a elif a['etag'] != status_etag_a: # item was updated in a
prefetch_from_a.append(href_a)
actions.append(action_update(uid, 'a', 'b')) actions.append(action_update(uid, 'a', 'b'))
elif b['etag'] != status_etag_b: # item was updated in b elif b['etag'] != status_etag_b: # item was updated in b
prefetch_from_b.append(href_b)
actions.append(action_update(uid, 'b', 'a')) actions.append(action_update(uid, 'b', 'a'))
elif a and not b: # was deleted from b elif a and not b: # was deleted from b
actions.append(action_delete(uid, 'a')) actions.append(action_delete(uid, 'a'))
@ -228,4 +212,4 @@ def get_actions(storages, status):
elif not a and not b: # was deleted from a and b elif not a and not b: # was deleted from a and b
actions.append(action_delete(uid, None)) actions.append(action_delete(uid, None))
return actions, prefetch_from_a, prefetch_from_b return actions