async def clear_manifest(self, entry_id: EntryID) -> None: """ Raises: FSLocalMissError """ async with self._open_cursor() as cursor: # Safely remove from cache in_cache = bool(self._cache.pop(entry_id, None)) # Remove from local database cursor.execute("DELETE FROM vlobs WHERE vlob_id = ?", (entry_id.bytes, )) cursor.execute("SELECT changes()") deleted, = cursor.fetchone() # Clean all the pending chunks # TODO: should also add the content of the popped manifest pending_chunk_ids = self._cache_ahead_of_localdb.pop(entry_id, ()) for chunk_id in pending_chunk_ids: cursor.execute("DELETE FROM chunks WHERE chunk_id = ?", (chunk_id.bytes, )) # Raise a miss if the entry wasn't found if not deleted and not in_cache: raise FSLocalMissError(entry_id)
async def get_manifest(self, entry_id: EntryID) -> BaseLocalManifest: """Raises: FSLocalMissError""" assert isinstance(entry_id, EntryID) try: return self._cache[entry_id] except KeyError: raise FSLocalMissError(entry_id)
async def get_manifest(self, entry_id: EntryID) -> BaseLocalManifest: """ Raises: FSLocalMissError """ # Look in cache first try: return self._cache[entry_id] except KeyError: pass # Look into the database async with self._open_cursor() as cursor: cursor.execute("SELECT blob FROM vlobs WHERE vlob_id = ?", (entry_id.bytes, )) manifest_row = cursor.fetchone() # Not found if not manifest_row: raise FSLocalMissError(entry_id) # Safely fill the cache if entry_id not in self._cache: self._cache[entry_id] = BaseLocalManifest.decrypt_and_load( manifest_row[0], key=self.device.local_symkey) # Always return the cached value return self._cache[entry_id]
async def clear_chunk(self, chunk_id: ChunkID) -> None: async with self._open_cursor() as cursor: cursor.execute("DELETE FROM chunks WHERE chunk_id = ?", (chunk_id.bytes,)) cursor.execute("SELECT changes()") changes, = cursor.fetchone() if not changes: raise FSLocalMissError(chunk_id)
async def clear_chunk(self, chunk_id: ChunkID) -> None: async with self._open_cursor() as cursor: # Use a thread as executing a statement that modifies the content of the database might, # in some case, block for several hundreds of milliseconds await self.localdb.run_in_thread( cursor.execute, "DELETE FROM chunks WHERE chunk_id = ?", (chunk_id.bytes, )) cursor.execute("SELECT changes()") changes, = cursor.fetchone() if not changes: raise FSLocalMissError(chunk_id)
async def get_chunk(self, chunk_id: ChunkID) -> bytes: async with self._open_cursor() as cursor: cursor.execute( """ UPDATE chunks SET accessed_on = ? WHERE chunk_id = ?; """, (time.time(), chunk_id.bytes), ) cursor.execute("SELECT changes()") changes, = cursor.fetchone() if not changes: raise FSLocalMissError(chunk_id) cursor.execute("""SELECT data FROM chunks WHERE chunk_id = ?""", (chunk_id.bytes,)) ciphered, = cursor.fetchone() return self.local_symkey.decrypt(ciphered)
async def get_chunk(self, chunk_id: ChunkID) -> bytes: async with self._open_cursor() as cursor: # Use a thread as executing a statement that modifies the content of the database might, # in some case, block for several hundreds of milliseconds await self.localdb.run_in_thread( cursor.execute, """ UPDATE chunks SET accessed_on = ? WHERE chunk_id = ?; """, (time.time(), chunk_id.bytes), ) cursor.execute("SELECT changes()") changes, = cursor.fetchone() if not changes: raise FSLocalMissError(chunk_id) cursor.execute("""SELECT data FROM chunks WHERE chunk_id = ?""", (chunk_id.bytes, )) ciphered, = cursor.fetchone() return self.local_symkey.decrypt(ciphered)