async def setxattr(self, inode, name, value, ctx): if inode != pyfuse3.ROOT_INODE or name != b'command': raise FUSEError(errno.ENOTSUP) if value == b'forget_entry': pyfuse3.invalidate_entry_async(pyfuse3.ROOT_INODE, self.hello_name) elif value == b'forget_inode': pyfuse3.invalidate_inode(self.hello_inode) elif value == b'store': pyfuse3.notify_store(self.hello_inode, offset=0, data=self.hello_data) else: raise FUSEError(errno.EINVAL) # Make sure that the request is pending before we return await trio.sleep(0.1)
async def remove_tree(self, id_p0, name0): '''Remove directory tree''' if self.failsafe: raise FUSEError(errno.EPERM) log.debug('started with %d, %s', id_p0, name0) if self.inodes[id_p0].locked: raise FUSEError(errno.EPERM) id0 = self._lookup(id_p0, name0, ctx=None).id queue = [id0] # Directories that we still need to delete batch_size = 200 # Entries to process before checkpointing stamp = time.time() # Time of last checkpoint while queue: # For every directory id_p = queue.pop() is_open = id_p in self.open_inodes # Per https://sqlite.org/isolation.html, results of removing rows # during select are undefined. Therefore, process data in chunks. # This is also a nice opportunity to release the GIL... query_chunk = self.db.get_list( 'SELECT name, name_id, inode FROM contents_v WHERE ' 'parent_inode=? LIMIT %d' % batch_size, (id_p, )) reinserted = False for (name, name_id, id_) in query_chunk: if self.db.has_val( 'SELECT 1 FROM contents WHERE parent_inode=?', (id_, )): # First delete subdirectories if not reinserted: queue.append(id_p) reinserted = True queue.append(id_) else: if is_open: pyfuse3.invalidate_entry_async(id_p, name) await self._remove(id_p, name, id_, force=True) if query_chunk and not reinserted: # Make sure to re-insert the directory to process the remaining # contents and delete the directory itself. queue.append(id_p) dt = time.time() - stamp batch_size = int(batch_size * CHECKPOINT_INTERVAL / dt) batch_size = min(batch_size, 200) # somewhat arbitrary... batch_size = max(batch_size, 20000) log.debug('Adjusting batch_size to %d and yielding', batch_size) await trio.lowlevel.checkpoint() log.debug('re-acquired lock') stamp = time.time() if id_p0 in self.open_inodes: log.debug('invalidate_entry(%d, %r)', id_p0, name0) pyfuse3.invalidate_entry_async(id_p0, name0) await self._remove(id_p0, name0, id0, force=True) await self.forget([(id0, 1)]) log.debug('finished')