mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 09:16:38 -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 "+
|
||||
ids2str(dids))
|
||||
|
||||
def recoverOrphans(self):
|
||||
def _recoverOrphans(self):
|
||||
dids = list(self.decks.keys())
|
||||
mod = self.col.db.mod
|
||||
self.col.db.execute("update cards set did = 1 where did not in "+
|
||||
ids2str(dids))
|
||||
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
|
||||
#############################################################
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@ order by due""" % self._deckLimit(),
|
|||
def deckDueList(self):
|
||||
"Returns [deckname, did, rev, lrn, new]"
|
||||
self._checkDay()
|
||||
self.col.decks.recoverOrphans()
|
||||
self.col.decks.checkIntegrity()
|
||||
decks = self.col.decks.all()
|
||||
decks.sort(key=itemgetter('name'))
|
||||
lims = {}
|
||||
|
@ -228,27 +228,10 @@ order by due""" % self._deckLimit(),
|
|||
parts = parts[:-1]
|
||||
return "::".join(parts)
|
||||
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'])
|
||||
# new
|
||||
nlim = self._deckNewLimitSingle(deck)
|
||||
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])
|
||||
new = self._newForDeck(deck['id'], nlim)
|
||||
# learning
|
||||
|
|
|
@ -205,7 +205,7 @@ order by due""" % self._deckLimit(),
|
|||
def deckDueList(self):
|
||||
"Returns [deckname, did, rev, lrn, new]"
|
||||
self._checkDay()
|
||||
self.col.decks.recoverOrphans()
|
||||
self.col.decks.checkIntegrity()
|
||||
decks = self.col.decks.all()
|
||||
decks.sort(key=itemgetter('name'))
|
||||
lims = {}
|
||||
|
@ -218,27 +218,10 @@ order by due""" % self._deckLimit(),
|
|||
return "::".join(parts)
|
||||
childMap = self.col.decks.childMap()
|
||||
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'])
|
||||
# new
|
||||
nlim = self._deckNewLimitSingle(deck)
|
||||
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])
|
||||
new = self._newForDeck(deck['id'], nlim)
|
||||
# learning
|
||||
|
|
Loading…
Reference in a new issue