diff options
Diffstat (limited to 'src/s3ql/block_cache.py')
-rw-r--r-- | src/s3ql/block_cache.py | 55 |
1 files changed, 32 insertions, 23 deletions
diff --git a/src/s3ql/block_cache.py b/src/s3ql/block_cache.py index 4678260..a8ebb64 100644 --- a/src/s3ql/block_cache.py +++ b/src/s3ql/block_cache.py @@ -321,14 +321,14 @@ class BlockCache(object): else: self.mlock.release(obj_id, noerror=noerror) - def _lock_entry(self, inode, blockno, release_global=False): + def _lock_entry(self, inode, blockno, release_global=False, timeout=None): '''Acquire lock on cache entry''' if release_global: with lock_released: - self.mlock.acquire((inode, blockno)) + return self.mlock.acquire((inode, blockno), timeout=timeout) else: - self.mlock.acquire((inode, blockno)) + return self.mlock.acquire((inode, blockno), timeout=timeout) def _unlock_entry(self, inode, blockno, release_global=False, noerror=False): @@ -887,30 +887,39 @@ class BlockCache(object): if end_no is None: end_no = start_no + 1 - - for blockno in range(start_no, end_no): - self._lock_entry(inode, blockno, release_global=True) - try: - if (inode, blockno) in self.cache: - log.debug('removing from cache') - self.cache.remove((inode, blockno)) - - try: - block_id = self.db.get_val('SELECT block_id FROM inode_blocks ' - 'WHERE inode=? AND blockno=?', (inode, blockno)) - except NoSuchRowError: - log.debug('block not in db') + blocknos = set(range(start_no, end_no)) + + # First do an opportunistic pass and remove everything where we can + # immediately get a lock. This is important when removing a file right + # after it has been created. If the upload of the first block has + # already started , removal would be stuck behind the upload procedure, + # waiting for every block to be uploaded only to remove it afterwards. + for timeout in (0, None): + for blockno in list(blocknos): + if not self._lock_entry(inode, blockno, release_global=True, timeout=timeout): continue + blocknos.remove(blockno) + try: + if (inode, blockno) in self.cache: + log.debug('removing from cache') + self.cache.remove((inode, blockno)) + + try: + block_id = self.db.get_val('SELECT block_id FROM inode_blocks ' + 'WHERE inode=? AND blockno=?', (inode, blockno)) + except NoSuchRowError: + log.debug('block not in db') + continue - # Detach inode from block - self.db.execute('DELETE FROM inode_blocks WHERE inode=? AND blockno=?', - (inode, blockno)) + # Detach inode from block + self.db.execute('DELETE FROM inode_blocks WHERE inode=? AND blockno=?', + (inode, blockno)) - finally: - self._unlock_entry(inode, blockno, release_global=True) + finally: + self._unlock_entry(inode, blockno, release_global=True) - # Decrease block refcount - self._deref_block(block_id) + # Decrease block refcount + self._deref_block(block_id) log.debug('finished') |