For each hash that needs refreshing, finds all the files with that hash.
If the file has changed or is missing, it is removed from the table.
- @return: dictionary with keys the hashes, values a list of FilePaths
+ @return: a list of dictionaries of each hash needing refreshing, sorted by age
"""
t = datetime.now() - timedelta(seconds=expireAfter)
# Find all the hashes that need refreshing
c = self.conn.cursor()
- c.execute("SELECT hashID, hash, pieces FROM hashes WHERE refreshed < ?", (t, ))
+ c.execute("SELECT hashID, hash, pieces FROM hashes WHERE refreshed < ? ORDER BY refreshed", (t, ))
row = c.fetchone()
- expired = {}
+ expired = []
while row:
- res = expired.setdefault(row['hash'], {})
- res['hashID'] = row['hashID']
+ res = {}
res['hash'] = row['hash']
+ res['hashID'] = row['hashID']
res['pieces'] = row['pieces']
+ expired.append(res)
row = c.fetchone()
# Make sure there are still valid DHT files for each hash
- for hash in expired.values():
+ for i in xrange(len(expired)-1, -1, -1):
dht = False
non_dht = False
+ hash = expired[i]
c.execute("SELECT path, dht, size, mtime FROM files WHERE hashID = ?", (hash['hashID'], ))
row = c.fetchone()
while row:
- res = self._removeChanged(FilePath(row['path']), row)
- if res:
- if row['dht']:
- dht = True
- else:
- non_dht = True
+ if row['dht']:
+ dht = True
+ else:
+ non_dht = True
row = c.fetchone()
if not dht:
# Remove hashes for which no DHT files are still available
- del expired[hash['hash']]
+ del expired[i]
if not non_dht:
# Remove hashes for which no files are still available
c.execute("DELETE FROM hashes WHERE hashID = ?", (hash['hashID'], ))
# Delete all the removed files from the database
if removed:
c.execute("DELETE FROM files " + sql, newdirs)
+ self.conn.commit()
+
+ c.execute("SELECT path FROM files")
+ rows = c.fetchall()
+ for row in rows:
+ if not os.path.exists(row['path']):
+ # Leave hashes, they will be removed on next refresh
+ c.execute("DELETE FROM files WHERE path = ?", (row['path'], ))
+ removed.append(FilePath(row['path']))
self.conn.commit()
return removed
def test_expiry(self):
"""Tests retrieving the files from the database that have expired."""
res = self.store.expiredHashes(1)
- self.failUnlessEqual(len(res.keys()), 0)
+ self.failUnlessEqual(len(res), 0)
sleep(2)
res = self.store.expiredHashes(1)
- self.failUnlessEqual(len(res.keys()), 1)
- self.failUnlessEqual(res.keys()[0], self.hash)
+ self.failUnlessEqual(len(res), 1)
+ self.failUnlessEqual(res[0]['hash'], self.hash)
self.store.refreshHash(self.hash)
res = self.store.expiredHashes(1)
- self.failUnlessEqual(len(res.keys()), 0)
+ self.failUnlessEqual(len(res), 0)
def build_dirs(self):
for dir in self.dirs:
"""Tests looking up a hash with multiple files in the database."""
self.build_dirs()
res = self.store.expiredHashes(1)
- self.failUnlessEqual(len(res.keys()), 0)
+ self.failUnlessEqual(len(res), 0)
res = self.store.lookupHash(self.hash)
self.failUnless(res)
self.failUnlessEqual(len(res), 4)
self.failUnlessEqual(res[0]['refreshed'], res[3]['refreshed'])
sleep(2)
res = self.store.expiredHashes(1)
- self.failUnlessEqual(len(res.keys()), 1)
- self.failUnlessEqual(res.keys()[0], self.hash)
+ self.failUnlessEqual(len(res), 1)
+ self.failUnlessEqual(res[0]['hash'], self.hash)
self.store.refreshHash(self.hash)
res = self.store.expiredHashes(1)
- self.failUnlessEqual(len(res.keys()), 0)
+ self.failUnlessEqual(len(res), 0)
def test_removeUntracked(self):
"""Tests removing untracked files from the database."""
self.build_dirs()
+ file = self.dirs[0].child('test.khashmir')
+ file.setContent(file.path)
+ file.touch()
+ self.store.storeFile(file, self.hash)
res = self.store.removeUntrackedFiles(self.dirs)
self.failUnlessEqual(len(res), 1, 'Got removed paths: %r' % res)
self.failUnlessEqual(res[0], self.file, 'Got removed paths: %r' % res)
res = self.store.removeUntrackedFiles(self.dirs)
self.failUnlessEqual(len(res), 0, 'Got removed paths: %r' % res)
+ file.remove()
+ res = self.store.removeUntrackedFiles(self.dirs)
+ self.failUnlessEqual(len(res), 1, 'Got removed paths: %r' % res)
+ self.failUnlessEqual(res[0], self.dirs[0].child('test.khashmir'), 'Got removed paths: %r' % res)
res = self.store.removeUntrackedFiles(self.dirs[1:])
self.failUnlessEqual(len(res), 1, 'Got removed paths: %r' % res)
self.failUnlessEqual(res[0], self.dirs[0].preauthChild(self.testfile), 'Got removed paths: %r' % res)