mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 14:32:22 -04:00
add logging to some scheduling and syncing code
This commit is contained in:
parent
9baa3e197a
commit
b99533a5ad
5 changed files with 73 additions and 6 deletions
|
@ -1,6 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright: Damien Elmes <anki@ichi2.net>
|
# Copyright: Damien Elmes <anki@ichi2.net>
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
import pprint
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from anki.utils import intTime, timestampID, joinFields
|
from anki.utils import intTime, timestampID, joinFields
|
||||||
|
@ -106,6 +107,7 @@ insert or replace into cards values
|
||||||
self.odid,
|
self.odid,
|
||||||
self.flags,
|
self.flags,
|
||||||
self.data)
|
self.data)
|
||||||
|
self.col.log(self)
|
||||||
|
|
||||||
def flushSched(self):
|
def flushSched(self):
|
||||||
self.mod = intTime()
|
self.mod = intTime()
|
||||||
|
@ -121,6 +123,7 @@ lapses=?, left=?, odue=?, odid=?, did=? where id = ?""",
|
||||||
self.mod, self.usn, self.type, self.queue, self.due, self.ivl,
|
self.mod, self.usn, self.type, self.queue, self.due, self.ivl,
|
||||||
self.factor, self.reps, self.lapses,
|
self.factor, self.reps, self.lapses,
|
||||||
self.left, self.odue, self.odid, self.did, self.id)
|
self.left, self.odue, self.odid, self.did, self.id)
|
||||||
|
self.col.log(self)
|
||||||
|
|
||||||
def q(self, reload=False, browser=False):
|
def q(self, reload=False, browser=False):
|
||||||
return self.css() + self._getQA(reload, browser)['q']
|
return self.css() + self._getQA(reload, browser)['q']
|
||||||
|
@ -180,3 +183,12 @@ lapses=?, left=?, odue=?, odid=?, did=? where id = ?""",
|
||||||
self.model(), joinFields(self.note().fields))
|
self.model(), joinFields(self.note().fields))
|
||||||
if self.ord not in ords:
|
if self.ord not in ords:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
d = dict(self.__dict__)
|
||||||
|
# remove non-useful elements
|
||||||
|
del d['_note']
|
||||||
|
del d['_qa']
|
||||||
|
del d['col']
|
||||||
|
del d['timerStarted']
|
||||||
|
return pprint.pformat(d, width=300)
|
||||||
|
|
|
@ -51,6 +51,7 @@ class _Collection(object):
|
||||||
def __init__(self, db, server=False):
|
def __init__(self, db, server=False):
|
||||||
self.db = db
|
self.db = db
|
||||||
self.path = db._path
|
self.path = db._path
|
||||||
|
self.log(self.path, anki.version)
|
||||||
self.server = server
|
self.server = server
|
||||||
self._lastSave = time.time()
|
self._lastSave = time.time()
|
||||||
self.clearUndo()
|
self.clearUndo()
|
||||||
|
@ -205,7 +206,9 @@ crt=?, mod=?, scm=?, dty=?, usn=?, ls=?, conf=?""",
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def getCard(self, id):
|
def getCard(self, id):
|
||||||
return anki.cards.Card(self, id)
|
c = anki.cards.Card(self, id)
|
||||||
|
self.log(c)
|
||||||
|
return c
|
||||||
|
|
||||||
def getNote(self, id):
|
def getNote(self, id):
|
||||||
return anki.notes.Note(self, id=id)
|
return anki.notes.Note(self, id=id)
|
||||||
|
@ -767,3 +770,9 @@ and queue = 0""", intTime(), self.usn())
|
||||||
self.db.execute("vacuum")
|
self.db.execute("vacuum")
|
||||||
self.db.execute("analyze")
|
self.db.execute("analyze")
|
||||||
self.lock()
|
self.lock()
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
def log(self, *args):
|
||||||
|
runHook("log", args)
|
||||||
|
|
|
@ -55,6 +55,7 @@ class Scheduler(object):
|
||||||
self._haveQueues = True
|
self._haveQueues = True
|
||||||
|
|
||||||
def answerCard(self, card, ease):
|
def answerCard(self, card, ease):
|
||||||
|
self.col.log()
|
||||||
assert ease >= 1 and ease <= 4
|
assert ease >= 1 and ease <= 4
|
||||||
self.col.markReview(card)
|
self.col.markReview(card)
|
||||||
if self._burySiblingsOnAnswer:
|
if self._burySiblingsOnAnswer:
|
||||||
|
@ -142,14 +143,20 @@ order by due""" % self._deckLimit(),
|
||||||
def unburyCards(self):
|
def unburyCards(self):
|
||||||
"Unbury cards."
|
"Unbury cards."
|
||||||
self.col.conf['lastUnburied'] = self.today
|
self.col.conf['lastUnburied'] = self.today
|
||||||
|
self.col.log(
|
||||||
|
self.col.db.list("select id from cards where queue = -2"))
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set mod=?,usn=?,queue=type where queue = -2",
|
"update cards set mod=?,usn=?,queue=type where queue = -2",
|
||||||
intTime(), self.col.usn())
|
intTime(), self.col.usn())
|
||||||
|
|
||||||
def unburyCardsForDeck(self):
|
def unburyCardsForDeck(self):
|
||||||
|
sids = ids2str(self.col.decks.active())
|
||||||
|
self.col.log(
|
||||||
|
self.col.db.list("select id from cards where queue = -2 and did in %s"
|
||||||
|
% sids))
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set mod=?,usn=?,queue=type where queue = -2 and did in %s"
|
"update cards set mod=?,usn=?,queue=type where queue = -2 and did in %s"
|
||||||
% ids2str(self.col.decks.active()), intTime(), self.col.usn())
|
% sids, intTime(), self.col.usn())
|
||||||
|
|
||||||
# Rev/lrn/time daily stats
|
# Rev/lrn/time daily stats
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
@ -946,12 +953,14 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
ids = []
|
ids = []
|
||||||
return ids
|
return ids
|
||||||
# move the cards over
|
# move the cards over
|
||||||
|
self.col.log(deck['id'], ids)
|
||||||
self._moveToDyn(deck['id'], ids)
|
self._moveToDyn(deck['id'], ids)
|
||||||
return ids
|
return ids
|
||||||
|
|
||||||
def emptyDyn(self, did, lim=None):
|
def emptyDyn(self, did, lim=None):
|
||||||
if not lim:
|
if not lim:
|
||||||
lim = "did = %s" % did
|
lim = "did = %s" % did
|
||||||
|
self.col.log(self.col.db.list("select id from cards where %s" % lim))
|
||||||
# move out of cram queue
|
# move out of cram queue
|
||||||
self.col.db.execute("""
|
self.col.db.execute("""
|
||||||
update cards set did = odid, queue = (case when type = 1 then 0
|
update cards set did = odid, queue = (case when type = 1 then 0
|
||||||
|
@ -1242,6 +1251,7 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
|
|
||||||
def suspendCards(self, ids):
|
def suspendCards(self, ids):
|
||||||
"Suspend cards."
|
"Suspend cards."
|
||||||
|
self.col.log(ids)
|
||||||
self.remFromDyn(ids)
|
self.remFromDyn(ids)
|
||||||
self.removeLrn(ids)
|
self.removeLrn(ids)
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
|
@ -1250,6 +1260,7 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
|
|
||||||
def unsuspendCards(self, ids):
|
def unsuspendCards(self, ids):
|
||||||
"Unsuspend cards."
|
"Unsuspend cards."
|
||||||
|
self.col.log(ids)
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set queue=type,mod=?,usn=? "
|
"update cards set queue=type,mod=?,usn=? "
|
||||||
"where queue = -1 and id in "+ ids2str(ids),
|
"where queue = -1 and id in "+ ids2str(ids),
|
||||||
|
@ -1259,6 +1270,7 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
"Bury all cards for note until next session."
|
"Bury all cards for note until next session."
|
||||||
cids = self.col.db.list(
|
cids = self.col.db.list(
|
||||||
"select id from cards where nid = ? and queue >= 0", nid)
|
"select id from cards where nid = ? and queue >= 0", nid)
|
||||||
|
self.col.log(cids)
|
||||||
self.removeLrn(cids)
|
self.removeLrn(cids)
|
||||||
self.col.db.execute("""
|
self.col.db.execute("""
|
||||||
update cards set queue=-2,mod=?,usn=? where id in """+ids2str(cids),
|
update cards set queue=-2,mod=?,usn=? where id in """+ids2str(cids),
|
||||||
|
@ -1295,9 +1307,11 @@ and (queue=0 or (queue=2 and due<=?))""",
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
# then bury
|
# then bury
|
||||||
self.col.db.execute(
|
if toBury:
|
||||||
"update cards set queue=-2,mod=?,usn=? where id in "+ids2str(toBury),
|
self.col.db.execute(
|
||||||
intTime(), self.col.usn())
|
"update cards set queue=-2,mod=?,usn=? where id in "+ids2str(toBury),
|
||||||
|
intTime(), self.col.usn())
|
||||||
|
self.col.log(toBury)
|
||||||
|
|
||||||
# Resetting
|
# Resetting
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
@ -1311,6 +1325,7 @@ and (queue=0 or (queue=2 and due<=?))""",
|
||||||
"select max(due) from cards where type=0") or 0
|
"select max(due) from cards where type=0") or 0
|
||||||
# takes care of mod + usn
|
# takes care of mod + usn
|
||||||
self.sortCards(ids, start=pmax+1)
|
self.sortCards(ids, start=pmax+1)
|
||||||
|
self.col.log(ids)
|
||||||
|
|
||||||
def reschedCards(self, ids, imin, imax):
|
def reschedCards(self, ids, imin, imax):
|
||||||
"Put cards in review queue with a new interval in days (min, max)."
|
"Put cards in review queue with a new interval in days (min, max)."
|
||||||
|
@ -1326,6 +1341,7 @@ and (queue=0 or (queue=2 and due<=?))""",
|
||||||
update cards set type=2,queue=2,ivl=:ivl,due=:due,
|
update cards set type=2,queue=2,ivl=:ivl,due=:due,
|
||||||
usn=:usn, mod=:mod, factor=:fact where id=:id and odid=0 and queue >=0""",
|
usn=:usn, mod=:mod, factor=:fact where id=:id and odid=0 and queue >=0""",
|
||||||
d)
|
d)
|
||||||
|
self.col.log(ids)
|
||||||
|
|
||||||
def resetCards(self, ids):
|
def resetCards(self, ids):
|
||||||
"Completely reset cards for export."
|
"Completely reset cards for export."
|
||||||
|
@ -1335,6 +1351,7 @@ usn=:usn, mod=:mod, factor=:fact where id=:id and odid=0 and queue >=0""",
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set reps=0, lapses=0 where id in " + ids2str(nonNew))
|
"update cards set reps=0, lapses=0 where id in " + ids2str(nonNew))
|
||||||
self.forgetCards(nonNew)
|
self.forgetCards(nonNew)
|
||||||
|
self.col.log(ids)
|
||||||
|
|
||||||
# Repositioning new cards
|
# Repositioning new cards
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
@ -1377,6 +1394,7 @@ and due >= ? and queue = 0""" % scids, now, self.col.usn(), shiftby, low)
|
||||||
d.append(dict(now=now, due=due[nid], usn=self.col.usn(), cid=id))
|
d.append(dict(now=now, due=due[nid], usn=self.col.usn(), cid=id))
|
||||||
self.col.db.executemany(
|
self.col.db.executemany(
|
||||||
"update cards set due=:due,mod=:now,usn=:usn where id = :cid", d)
|
"update cards set due=:due,mod=:now,usn=:usn where id = :cid", d)
|
||||||
|
self.col.log(cids)
|
||||||
|
|
||||||
def randomizeCards(self, did):
|
def randomizeCards(self, did):
|
||||||
cids = self.col.db.list("select id from cards where did = ?", did)
|
cids = self.col.db.list("select id from cards where did = ?", did)
|
||||||
|
|
|
@ -105,6 +105,7 @@ class Syncer(object):
|
||||||
# step 1: login & metadata
|
# step 1: login & metadata
|
||||||
runHook("sync", "login")
|
runHook("sync", "login")
|
||||||
meta = self.server.meta()
|
meta = self.server.meta()
|
||||||
|
self.col.log("rmeta", meta)
|
||||||
if not meta:
|
if not meta:
|
||||||
return "badAuth"
|
return "badAuth"
|
||||||
rscm = meta['scm']
|
rscm = meta['scm']
|
||||||
|
@ -125,19 +126,24 @@ class Syncer(object):
|
||||||
# and require confirmation if it's non-empty
|
# and require confirmation if it's non-empty
|
||||||
pass
|
pass
|
||||||
meta = self.meta()
|
meta = self.meta()
|
||||||
|
self.col.log("lmeta", meta)
|
||||||
self.lmod = meta['mod']
|
self.lmod = meta['mod']
|
||||||
self.minUsn = meta['usn']
|
self.minUsn = meta['usn']
|
||||||
lscm = meta['scm']
|
lscm = meta['scm']
|
||||||
lts = meta['ts']
|
lts = meta['ts']
|
||||||
if abs(rts - lts) > 300:
|
if abs(rts - lts) > 300:
|
||||||
|
self.col.log("clock off")
|
||||||
return "clockOff"
|
return "clockOff"
|
||||||
if self.lmod == self.rmod:
|
if self.lmod == self.rmod:
|
||||||
|
self.col.log("no changes")
|
||||||
return "noChanges"
|
return "noChanges"
|
||||||
elif lscm != rscm:
|
elif lscm != rscm:
|
||||||
|
self.col.log("schema diff")
|
||||||
return "fullSync"
|
return "fullSync"
|
||||||
self.lnewer = self.lmod > self.rmod
|
self.lnewer = self.lmod > self.rmod
|
||||||
# step 1.5: check collection is valid
|
# step 1.5: check collection is valid
|
||||||
if not self.col.basicCheck():
|
if not self.col.basicCheck():
|
||||||
|
self.col.log("basic check")
|
||||||
return "basicCheckFailed"
|
return "basicCheckFailed"
|
||||||
# step 2: deletions
|
# step 2: deletions
|
||||||
runHook("sync", "meta")
|
runHook("sync", "meta")
|
||||||
|
@ -154,6 +160,7 @@ class Syncer(object):
|
||||||
while 1:
|
while 1:
|
||||||
runHook("sync", "stream")
|
runHook("sync", "stream")
|
||||||
chunk = self.server.chunk()
|
chunk = self.server.chunk()
|
||||||
|
self.col.log("server chunk", chunk)
|
||||||
self.applyChunk(chunk=chunk)
|
self.applyChunk(chunk=chunk)
|
||||||
if chunk['done']:
|
if chunk['done']:
|
||||||
break
|
break
|
||||||
|
@ -162,6 +169,7 @@ class Syncer(object):
|
||||||
while 1:
|
while 1:
|
||||||
runHook("sync", "stream")
|
runHook("sync", "stream")
|
||||||
chunk = self.chunk()
|
chunk = self.chunk()
|
||||||
|
self.col.log("client chunk", chunk)
|
||||||
self.server.applyChunk(chunk=chunk)
|
self.server.applyChunk(chunk=chunk)
|
||||||
if chunk['done']:
|
if chunk['done']:
|
||||||
break
|
break
|
||||||
|
@ -478,6 +486,7 @@ from notes where %s""" % d)
|
||||||
for r in data:
|
for r in data:
|
||||||
if r[0] not in lmods or lmods[r[0]] < r[modIdx]:
|
if r[0] not in lmods or lmods[r[0]] < r[modIdx]:
|
||||||
update.append(r)
|
update.append(r)
|
||||||
|
self.col.log(table, data)
|
||||||
return update
|
return update
|
||||||
|
|
||||||
def mergeCards(self, cards):
|
def mergeCards(self, cards):
|
||||||
|
|
21
aqt/main.py
21
aqt/main.py
|
@ -3,6 +3,7 @@
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -269,7 +270,8 @@ To import into a password protected profile, please open the profile before atte
|
||||||
showWarning("""\
|
showWarning("""\
|
||||||
Your collection is corrupt. Please see the manual for \
|
Your collection is corrupt. Please see the manual for \
|
||||||
how to restore from a backup.""")
|
how to restore from a backup.""")
|
||||||
return self.unloadProfile()
|
self.unloadProfile()
|
||||||
|
raise
|
||||||
self.hideSchemaMsg = False
|
self.hideSchemaMsg = False
|
||||||
self.progress.setupDB(self.col.db)
|
self.progress.setupDB(self.col.db)
|
||||||
self.maybeEnableUndo()
|
self.maybeEnableUndo()
|
||||||
|
@ -837,6 +839,7 @@ the problem and restart Anki.""")
|
||||||
def setupHooks(self):
|
def setupHooks(self):
|
||||||
addHook("modSchema", self.onSchemaMod)
|
addHook("modSchema", self.onSchemaMod)
|
||||||
addHook("remNotes", self.onRemNotes)
|
addHook("remNotes", self.onRemNotes)
|
||||||
|
addHook("log", self.onLog)
|
||||||
|
|
||||||
# Log note deletion
|
# Log note deletion
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
@ -854,6 +857,22 @@ the problem and restart Anki.""")
|
||||||
f.write(("\t".join([str(id), str(mid)] + fields)).encode("utf8"))
|
f.write(("\t".join([str(id), str(mid)] + fields)).encode("utf8"))
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
|
|
||||||
|
# Debug logging
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
def onLog(self, args):
|
||||||
|
def customRepr(x):
|
||||||
|
if isinstance(x, basestring):
|
||||||
|
return x
|
||||||
|
return pprint.pformat(x)
|
||||||
|
path, num, fn, y = traceback.extract_stack(limit=4)[0]
|
||||||
|
buf = "[%s] %s:%s(): %s" % (intTime(), os.path.basename(path), fn,
|
||||||
|
", ".join([customRepr(x) for x in args]))
|
||||||
|
lpath = re.sub("\.anki2$", ".log", self.pm.collectionPath())
|
||||||
|
open(lpath, "ab").write(buf + "\n")
|
||||||
|
if os.environ.get("LOG"):
|
||||||
|
print buf
|
||||||
|
|
||||||
# Schema modifications
|
# Schema modifications
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue