From 9a6f2be2b67e4b96e57dd9476e053d0d7fc07265 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Wed, 30 Oct 2019 10:17:09 +1000 Subject: [PATCH] force a full sync when fields or templates changed without schema mod This is not an ideal solution and will not catch repositioned fields or templates, but is at least an improvement over the previous behaviour. https://github.com/dae/anki/pull/349#issuecomment-547236285 --- anki/sync.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/anki/sync.py b/anki/sync.py index f5d21e89d..c3ce9baf2 100644 --- a/anki/sync.py +++ b/anki/sync.py @@ -22,6 +22,9 @@ HTTP_TIMEOUT = 90 HTTP_PROXY = None HTTP_BUF_SIZE = 64*1024 +class UnexpectedSchemaChange(Exception): + pass + # Incremental syncing ########################################################################## @@ -95,7 +98,11 @@ class Syncer: # ...and small objects lchg = self.changes() rchg = self.server.applyChanges(changes=lchg) - self.mergeChanges(lchg, rchg) + try: + self.mergeChanges(lchg, rchg) + except UnexpectedSchemaChange: + self.server.abort() + return self._forceFullSync() # step 3: stream large tables from server runHook("sync", "server") while 1: @@ -119,17 +126,20 @@ class Syncer: c = self.sanityCheck() ret = self.server.sanityCheck2(client=c) if ret['status'] != "ok": - # roll back and force full sync - self.col.rollback() - self.col.modSchema(False) - self.col.save() - return "sanityCheckFailed" + return self._forceFullSync() # finalize runHook("sync", "finalize") mod = self.server.finish() self.finish(mod) return "success" + def _forceFullSync(self): + # roll back and force full sync + self.col.rollback() + self.col.modSchema(False) + self.col.save() + return "sanityCheckFailed" + def _gravesChunk(self, graves): lim = 250 chunk = dict(notes=[], cards=[], decks=[]) @@ -330,6 +340,14 @@ from notes where %s""" % d) l = self.col.models.get(r['id']) # if missing locally or server is newer, update if not l or r['mod'] > l['mod']: + # This is a hack to detect when the note type has been altered + # in an import without a full sync being forced. A future + # syncing algorithm should handle this in a better way. + if l: + if len(l['flds']) != len(r['flds']): + raise UnexpectedSchemaChange() + if len(l['tmpls']) != len(r['tmpls']): + raise UnexpectedSchemaChange() self.col.models.update(r) # Decks