mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 01:06:35 -04:00
improve handling of invalid deck trees
- move checking code out of the schedulers and into the deck manager - ensure we can fix the problem in one loop - the previous recursive approach could lead to stack overflows if the top level of a large deck tree was missing. this was also the cause of the sqlite 'interrupted' error that some users were seeing
This commit is contained in:
parent
5e5d35e9c1
commit
9c85376b3e
3 changed files with 35 additions and 37 deletions
|
@ -432,13 +432,45 @@ class DeckManager:
|
||||||
return self.col.db.list("select id from cards where did in "+
|
return self.col.db.list("select id from cards where did in "+
|
||||||
ids2str(dids))
|
ids2str(dids))
|
||||||
|
|
||||||
def recoverOrphans(self):
|
def _recoverOrphans(self):
|
||||||
dids = list(self.decks.keys())
|
dids = list(self.decks.keys())
|
||||||
mod = self.col.db.mod
|
mod = self.col.db.mod
|
||||||
self.col.db.execute("update cards set did = 1 where did not in "+
|
self.col.db.execute("update cards set did = 1 where did not in "+
|
||||||
ids2str(dids))
|
ids2str(dids))
|
||||||
self.col.db.mod = mod
|
self.col.db.mod = mod
|
||||||
|
|
||||||
|
def _checkDeckTree(self):
|
||||||
|
decks = self.col.decks.all()
|
||||||
|
decks.sort(key=operator.itemgetter('name'))
|
||||||
|
names = set()
|
||||||
|
|
||||||
|
for deck in decks:
|
||||||
|
# two decks with the same name?
|
||||||
|
if deck['name'] in names:
|
||||||
|
print("fix duplicate deck name", deck['name'])
|
||||||
|
deck['name'] += "%d" % intTime(1000)
|
||||||
|
self.save(deck)
|
||||||
|
|
||||||
|
# ensure no sections are blank
|
||||||
|
if not all(deck['name'].split("::")):
|
||||||
|
print("fix deck with missing sections", deck['name'])
|
||||||
|
deck['name'] = "recovered%d" % intTime(1000)
|
||||||
|
self.save(deck)
|
||||||
|
|
||||||
|
# immediate parent must exist
|
||||||
|
if "::" in deck['name']:
|
||||||
|
immediateParent = "::".join(deck['name'].split("::")[:-1])
|
||||||
|
if immediateParent not in names:
|
||||||
|
print("fix deck with missing parent", deck['name'])
|
||||||
|
self._ensureParents(deck['name'])
|
||||||
|
names.add(immediateParent)
|
||||||
|
|
||||||
|
names.add(deck['name'])
|
||||||
|
|
||||||
|
def checkIntegrity(self):
|
||||||
|
self._recoverOrphans()
|
||||||
|
self._checkDeckTree()
|
||||||
|
|
||||||
# Deck selection
|
# Deck selection
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
|
|
|
@ -216,7 +216,7 @@ order by due""" % self._deckLimit(),
|
||||||
def deckDueList(self):
|
def deckDueList(self):
|
||||||
"Returns [deckname, did, rev, lrn, new]"
|
"Returns [deckname, did, rev, lrn, new]"
|
||||||
self._checkDay()
|
self._checkDay()
|
||||||
self.col.decks.recoverOrphans()
|
self.col.decks.checkIntegrity()
|
||||||
decks = self.col.decks.all()
|
decks = self.col.decks.all()
|
||||||
decks.sort(key=itemgetter('name'))
|
decks.sort(key=itemgetter('name'))
|
||||||
lims = {}
|
lims = {}
|
||||||
|
@ -228,27 +228,10 @@ order by due""" % self._deckLimit(),
|
||||||
parts = parts[:-1]
|
parts = parts[:-1]
|
||||||
return "::".join(parts)
|
return "::".join(parts)
|
||||||
for deck in decks:
|
for deck in decks:
|
||||||
# if we've already seen the exact same deck name, rename the
|
|
||||||
# invalid duplicate and reload
|
|
||||||
if deck['name'] in lims:
|
|
||||||
deck['name'] += "1"
|
|
||||||
self.col.decks.save(deck)
|
|
||||||
return self.deckDueList()
|
|
||||||
# ensure no sections are blank
|
|
||||||
if not all(deck['name'].split("::")):
|
|
||||||
deck['name'] = "recovered"
|
|
||||||
self.col.decks.save(deck)
|
|
||||||
return self.deckDueList()
|
|
||||||
|
|
||||||
p = parent(deck['name'])
|
p = parent(deck['name'])
|
||||||
# new
|
# new
|
||||||
nlim = self._deckNewLimitSingle(deck)
|
nlim = self._deckNewLimitSingle(deck)
|
||||||
if p:
|
if p:
|
||||||
if p not in lims:
|
|
||||||
# if parent was missing, this deck is invalid
|
|
||||||
deck['name'] = "recovered"
|
|
||||||
self.col.decks.save(deck)
|
|
||||||
return self.deckDueList()
|
|
||||||
nlim = min(nlim, lims[p][0])
|
nlim = min(nlim, lims[p][0])
|
||||||
new = self._newForDeck(deck['id'], nlim)
|
new = self._newForDeck(deck['id'], nlim)
|
||||||
# learning
|
# learning
|
||||||
|
|
|
@ -205,7 +205,7 @@ order by due""" % self._deckLimit(),
|
||||||
def deckDueList(self):
|
def deckDueList(self):
|
||||||
"Returns [deckname, did, rev, lrn, new]"
|
"Returns [deckname, did, rev, lrn, new]"
|
||||||
self._checkDay()
|
self._checkDay()
|
||||||
self.col.decks.recoverOrphans()
|
self.col.decks.checkIntegrity()
|
||||||
decks = self.col.decks.all()
|
decks = self.col.decks.all()
|
||||||
decks.sort(key=itemgetter('name'))
|
decks.sort(key=itemgetter('name'))
|
||||||
lims = {}
|
lims = {}
|
||||||
|
@ -218,27 +218,10 @@ order by due""" % self._deckLimit(),
|
||||||
return "::".join(parts)
|
return "::".join(parts)
|
||||||
childMap = self.col.decks.childMap()
|
childMap = self.col.decks.childMap()
|
||||||
for deck in decks:
|
for deck in decks:
|
||||||
# if we've already seen the exact same deck name, rename the
|
|
||||||
# invalid duplicate and reload
|
|
||||||
if deck['name'] in lims:
|
|
||||||
deck['name'] += "1"
|
|
||||||
self.col.decks.save(deck)
|
|
||||||
return self.deckDueList()
|
|
||||||
# ensure no sections are blank
|
|
||||||
if not all(deck['name'].split("::")):
|
|
||||||
deck['name'] = "recovered"
|
|
||||||
self.col.decks.save(deck)
|
|
||||||
return self.deckDueList()
|
|
||||||
|
|
||||||
p = parent(deck['name'])
|
p = parent(deck['name'])
|
||||||
# new
|
# new
|
||||||
nlim = self._deckNewLimitSingle(deck)
|
nlim = self._deckNewLimitSingle(deck)
|
||||||
if p:
|
if p:
|
||||||
if p not in lims:
|
|
||||||
# if parent was missing, this deck is invalid
|
|
||||||
deck['name'] = "recovered"
|
|
||||||
self.col.decks.save(deck)
|
|
||||||
return self.deckDueList()
|
|
||||||
nlim = min(nlim, lims[p][0])
|
nlim = min(nlim, lims[p][0])
|
||||||
new = self._newForDeck(deck['id'], nlim)
|
new = self._newForDeck(deck['id'], nlim)
|
||||||
# learning
|
# learning
|
||||||
|
|
Loading…
Reference in a new issue