mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 23:12:21 -04:00
refactor to support early exit when no media changes
- regular sync now receives a media USN as well - server bumps media usn not only on sync but any other media change - added local media.hasChanged()
This commit is contained in:
parent
dd37ee5915
commit
0c85acf3f7
3 changed files with 31 additions and 17 deletions
|
@ -175,6 +175,9 @@ If the same name exists, compare checksums."""
|
||||||
def clearLog(self):
|
def clearLog(self):
|
||||||
self.db.execute("delete from log")
|
self.db.execute("delete from log")
|
||||||
|
|
||||||
|
def hasChanged(self):
|
||||||
|
return self.db.scalar("select 1 from log limit 1")
|
||||||
|
|
||||||
# Tracking changes (private)
|
# Tracking changes (private)
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
|
|
24
anki/sync.py
24
anki/sync.py
|
@ -47,8 +47,8 @@ class Syncer(object):
|
||||||
"Returns 'noChanges', 'fullSync', or 'success'."
|
"Returns 'noChanges', 'fullSync', or 'success'."
|
||||||
# step 1: login & metadata
|
# step 1: login & metadata
|
||||||
self.status("login")
|
self.status("login")
|
||||||
self.rmod, rscm, self.maxUsn, rts = self.server.meta()
|
self.rmod, rscm, self.maxUsn, rts, self.mediaUsn = self.server.meta()
|
||||||
self.lmod, lscm, self.minUsn, lts = self.meta()
|
self.lmod, lscm, self.minUsn, lts, dummy = self.meta()
|
||||||
if abs(rts - lts) > 300:
|
if abs(rts - lts) > 300:
|
||||||
return "clockOff"
|
return "clockOff"
|
||||||
if self.lmod == self.rmod:
|
if self.lmod == self.rmod:
|
||||||
|
@ -90,7 +90,7 @@ class Syncer(object):
|
||||||
return "success"
|
return "success"
|
||||||
|
|
||||||
def meta(self):
|
def meta(self):
|
||||||
return (self.deck.mod, self.deck.scm, self.deck._usn, intTime())
|
return (self.deck.mod, self.deck.scm, self.deck._usn, intTime(), None)
|
||||||
|
|
||||||
def changes(self):
|
def changes(self):
|
||||||
"Bundle up deletions and small objects, and apply if server."
|
"Bundle up deletions and small objects, and apply if server."
|
||||||
|
@ -535,21 +535,25 @@ class MediaSyncer(object):
|
||||||
self.server = server
|
self.server = server
|
||||||
self.added = None
|
self.added = None
|
||||||
|
|
||||||
def sync(self):
|
def sync(self, mediaUsn):
|
||||||
# step 1: send/recv deletions
|
# step 1: check if there have been any changes
|
||||||
|
self.deck.media.findChanges()
|
||||||
|
lusn = self.deck.media.usn()
|
||||||
|
if lusn == mediaUsn and not self.deck.media.hasChanged():
|
||||||
|
return "noChanges"
|
||||||
|
# step 2: send/recv deletions
|
||||||
runHook("mediaSync", "remove")
|
runHook("mediaSync", "remove")
|
||||||
usn = self.deck.media.usn()
|
|
||||||
lrem = self.removed()
|
lrem = self.removed()
|
||||||
rrem = self.server.remove(fnames=lrem, minUsn=usn)
|
rrem = self.server.remove(fnames=lrem, minUsn=lusn)
|
||||||
self.remove(rrem)
|
self.remove(rrem)
|
||||||
# step 2: stream files from server
|
# step 3: stream files from server
|
||||||
runHook("mediaSync", "server")
|
runHook("mediaSync", "server")
|
||||||
while 1:
|
while 1:
|
||||||
runHook("mediaSync", "stream")
|
runHook("mediaSync", "stream")
|
||||||
zip = self.server.files()
|
zip = self.server.files()
|
||||||
if self.addFiles(zip=zip) != "continue":
|
if self.addFiles(zip=zip) != "continue":
|
||||||
break
|
break
|
||||||
# step 3: stream files to the server
|
# step 4: stream files to the server
|
||||||
runHook("mediaSync", "client")
|
runHook("mediaSync", "client")
|
||||||
while 1:
|
while 1:
|
||||||
runHook("mediaSync", "stream")
|
runHook("mediaSync", "stream")
|
||||||
|
@ -558,10 +562,12 @@ class MediaSyncer(object):
|
||||||
if usn != "continue":
|
if usn != "continue":
|
||||||
# when server has run out of files, it returns bumped usn
|
# when server has run out of files, it returns bumped usn
|
||||||
break
|
break
|
||||||
|
# step 5: finalize
|
||||||
self.deck.media.setUsn(usn)
|
self.deck.media.setUsn(usn)
|
||||||
self.deck.media.clearLog()
|
self.deck.media.clearLog()
|
||||||
# clear cursor so successive calls work
|
# clear cursor so successive calls work
|
||||||
self.added = None
|
self.added = None
|
||||||
|
return "success"
|
||||||
|
|
||||||
def removed(self):
|
def removed(self):
|
||||||
return self.deck.media.removed()
|
return self.deck.media.removed()
|
||||||
|
|
|
@ -19,6 +19,7 @@ deck1=None
|
||||||
deck2=None
|
deck2=None
|
||||||
client=None
|
client=None
|
||||||
server=None
|
server=None
|
||||||
|
server2=None
|
||||||
|
|
||||||
def setup_basic():
|
def setup_basic():
|
||||||
global deck1, deck2, client, server
|
global deck1, deck2, client, server
|
||||||
|
@ -271,7 +272,7 @@ def setup_remote():
|
||||||
def test_meta():
|
def test_meta():
|
||||||
global TEST_REMOTE
|
global TEST_REMOTE
|
||||||
try:
|
try:
|
||||||
(mod, scm, usn, ts) = server.meta()
|
(mod, scm, usn, ts, dummy) = server.meta()
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
if e.errno == 61:
|
if e.errno == 61:
|
||||||
TEST_REMOTE = False
|
TEST_REMOTE = False
|
||||||
|
@ -330,9 +331,10 @@ def test_remoteSync():
|
||||||
# the current directory is the media folder.
|
# the current directory is the media folder.
|
||||||
|
|
||||||
def setup_remoteMedia():
|
def setup_remoteMedia():
|
||||||
global client, server
|
global client, server, server2
|
||||||
setup_basic()
|
setup_basic()
|
||||||
server = RemoteMediaServer(TEST_HKEY)
|
server = RemoteMediaServer(TEST_HKEY)
|
||||||
|
server2 = RemoteServer(TEST_USER, TEST_HKEY)
|
||||||
client = MediaSyncer(deck1, server)
|
client = MediaSyncer(deck1, server)
|
||||||
|
|
||||||
@nose.with_setup(setup_remoteMedia)
|
@nose.with_setup(setup_remoteMedia)
|
||||||
|
@ -340,26 +342,29 @@ def test_media():
|
||||||
server.mediatest("reset")
|
server.mediatest("reset")
|
||||||
assert len(os.listdir(deck1.media.dir())) == 0
|
assert len(os.listdir(deck1.media.dir())) == 0
|
||||||
assert server.mediatest("count") == 0
|
assert server.mediatest("count") == 0
|
||||||
|
# initially, nothing to do
|
||||||
|
assert client.sync(server2.meta()[4]) == "noChanges"
|
||||||
# add a file
|
# add a file
|
||||||
|
time.sleep(1)
|
||||||
os.chdir(deck1.media.dir())
|
os.chdir(deck1.media.dir())
|
||||||
p = os.path.join(deck1.media.dir(), "foo.jpg")
|
p = os.path.join(deck1.media.dir(), "foo.jpg")
|
||||||
open(p, "wb").write("foo")
|
open(p, "wb").write("foo")
|
||||||
assert len(os.listdir(deck1.media.dir())) == 1
|
assert len(os.listdir(deck1.media.dir())) == 1
|
||||||
assert server.mediatest("count") == 0
|
assert server.mediatest("count") == 0
|
||||||
client.sync()
|
assert client.sync(server2.meta()[4]) == "success"
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
# should have been synced
|
# should have been synced
|
||||||
assert len(os.listdir(deck1.media.dir())) == 1
|
assert len(os.listdir(deck1.media.dir())) == 1
|
||||||
assert server.mediatest("count") == 1
|
assert server.mediatest("count") == 1
|
||||||
# if we remove the file, should be removed
|
# if we remove the file, should be removed
|
||||||
os.unlink(p)
|
os.unlink(p)
|
||||||
client.sync()
|
assert client.sync(server2.meta()[4]) == "success"
|
||||||
assert len(os.listdir(deck1.media.dir())) == 0
|
assert len(os.listdir(deck1.media.dir())) == 0
|
||||||
assert server.mediatest("count") == 0
|
assert server.mediatest("count") == 0
|
||||||
# we should be able to add it again
|
# we should be able to add it again
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
open(p, "wb").write("foo")
|
open(p, "wb").write("foo")
|
||||||
client.sync()
|
assert client.sync(server2.meta()[4]) == "success"
|
||||||
assert len(os.listdir(deck1.media.dir())) == 1
|
assert len(os.listdir(deck1.media.dir())) == 1
|
||||||
assert server.mediatest("count") == 1
|
assert server.mediatest("count") == 1
|
||||||
# if we modify it, it should get sent too. also we set the zip size very
|
# if we modify it, it should get sent too. also we set the zip size very
|
||||||
|
@ -369,7 +374,7 @@ def test_media():
|
||||||
open(p, "wb").write("bar")
|
open(p, "wb").write("bar")
|
||||||
open(p+"2", "wb").write("baz")
|
open(p+"2", "wb").write("baz")
|
||||||
assert len(os.listdir(deck1.media.dir())) == 2
|
assert len(os.listdir(deck1.media.dir())) == 2
|
||||||
client.sync()
|
client.sync(server2.meta()[4])
|
||||||
assert len(os.listdir(deck1.media.dir())) == 2
|
assert len(os.listdir(deck1.media.dir())) == 2
|
||||||
assert server.mediatest("count") == 2
|
assert server.mediatest("count") == 2
|
||||||
# if we lose our media db, we should be able to bring it back in sync
|
# if we lose our media db, we should be able to bring it back in sync
|
||||||
|
@ -379,12 +384,12 @@ def test_media():
|
||||||
deck1.media.connect()
|
deck1.media.connect()
|
||||||
changes = deck1.media.added().fetchall()
|
changes = deck1.media.added().fetchall()
|
||||||
assert len(changes) == 2
|
assert len(changes) == 2
|
||||||
client.sync()
|
client.sync(server2.meta()[4])
|
||||||
assert len(os.listdir(deck1.media.dir())) == 2
|
assert len(os.listdir(deck1.media.dir())) == 2
|
||||||
assert server.mediatest("count") == 2
|
assert server.mediatest("count") == 2
|
||||||
# if we send an unchanged file, the server should cope
|
# if we send an unchanged file, the server should cope
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
deck1.media.db.execute("insert into log values ('foo.jpg', 0)")
|
deck1.media.db.execute("insert into log values ('foo.jpg', 0)")
|
||||||
client.sync()
|
client.sync(server2.meta()[4])
|
||||||
assert len(os.listdir(deck1.media.dir())) == 2
|
assert len(os.listdir(deck1.media.dir())) == 2
|
||||||
assert server.mediatest("count") == 2
|
assert server.mediatest("count") == 2
|
||||||
|
|
Loading…
Reference in a new issue