| 
														
															@@ -41,6 +41,12 @@ else: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         llfuse.main(single=True) 
														 | 
														
														 | 
														
															         llfuse.main(single=True) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         return None 
														 | 
														
														 | 
														
															         return None 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+# size of some LRUCaches (1 element per simultaneously open file) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+# note: _inode_cache might have rather large elements - Item.chunks can be large! 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+#       also, simultaneously reading too many files should be avoided anyway. 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+#       thus, do not set FILES to high values. 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+FILES = 4 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+ 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 class ItemCache: 
														 | 
														
														 | 
														
															 class ItemCache: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     """ 
														 | 
														
														 | 
														
															     """ 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -234,6 +240,8 @@ class FuseOperations(llfuse.Operations): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         # in the archives. For example archive directories or intermediate directories 
														 | 
														
														 | 
														
															         # in the archives. For example archive directories or intermediate directories 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         # not contained in archives. 
														 | 
														
														 | 
														
															         # not contained in archives. 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         self.items = {} 
														 | 
														
														 | 
														
															         self.items = {} 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        # cache up to <FILES> Items 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        self._inode_cache = LRUCache(capacity=FILES, dispose=lambda _: None) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         # _inode_count is the current count of synthetic inodes, i.e. those in self.items 
														 | 
														
														 | 
														
															         # _inode_count is the current count of synthetic inodes, i.e. those in self.items 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         self._inode_count = 0 
														 | 
														
														 | 
														
															         self._inode_count = 0 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         # Maps inode numbers to the inode number of the parent 
														 | 
														
														 | 
														
															         # Maps inode numbers to the inode number of the parent 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -249,6 +257,7 @@ class FuseOperations(llfuse.Operations): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         data_cache_capacity = int(os.environ.get('BORG_MOUNT_DATA_CACHE_ENTRIES', os.cpu_count() or 1)) 
														 | 
														
														 | 
														
															         data_cache_capacity = int(os.environ.get('BORG_MOUNT_DATA_CACHE_ENTRIES', os.cpu_count() or 1)) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         logger.debug('mount data cache capacity: %d chunks', data_cache_capacity) 
														 | 
														
														 | 
														
															         logger.debug('mount data cache capacity: %d chunks', data_cache_capacity) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         self.data_cache = LRUCache(capacity=data_cache_capacity, dispose=lambda _: None) 
														 | 
														
														 | 
														
															         self.data_cache = LRUCache(capacity=data_cache_capacity, dispose=lambda _: None) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        self._last_pos = LRUCache(capacity=FILES, dispose=lambda _: None) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															     def _create_filesystem(self): 
														 | 
														
														 | 
														
															     def _create_filesystem(self): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         self._create_dir(parent=1)  # first call, create root dir (inode == 1) 
														 | 
														
														 | 
														
															         self._create_dir(parent=1)  # first call, create root dir (inode == 1) 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -512,10 +521,17 @@ class FuseOperations(llfuse.Operations): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         return stat_ 
														 | 
														
														 | 
														
															         return stat_ 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															     def get_item(self, inode): 
														 | 
														
														 | 
														
															     def get_item(self, inode): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        item = self._inode_cache.get(inode) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        if item is not None: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            return item 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         try: 
														 | 
														
														 | 
														
															         try: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            # this is a cheap get-from-dictionary operation, no need to cache the result. 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             return self.items[inode] 
														 | 
														
														 | 
														
															             return self.items[inode] 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         except KeyError: 
														 | 
														
														 | 
														
															         except KeyError: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-            return self.cache.get(inode) 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            # while self.cache does some internal caching, it has still quite some overhead, so we cache the result. 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            item = self.cache.get(inode) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            self._inode_cache[inode] = item 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            return item 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															     def _find_inode(self, path, prefix=[]): 
														 | 
														
														 | 
														
															     def _find_inode(self, path, prefix=[]): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         segments = prefix + path.split(b'/') 
														 | 
														
														 | 
														
															         segments = prefix + path.split(b'/') 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -603,9 +619,23 @@ class FuseOperations(llfuse.Operations): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     def read(self, fh, offset, size): 
														 | 
														
														 | 
														
															     def read(self, fh, offset, size): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         parts = [] 
														 | 
														
														 | 
														
															         parts = [] 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         item = self.get_item(fh) 
														 | 
														
														 | 
														
															         item = self.get_item(fh) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-        for id, s, csize in item.chunks: 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+ 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        # optimize for linear reads: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        # we cache the chunk number and the in-file offset of the chunk in _last_pos[fh] 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        chunk_no, chunk_offset = self._last_pos.get(fh, (0, 0)) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        if chunk_offset > offset: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            # this is not a linear read, so we lost track and need to start from beginning again... 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            chunk_no, chunk_offset = (0, 0) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+ 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        offset -= chunk_offset 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        chunks = item.chunks 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        # note: using index iteration to avoid frequently copying big (sub)lists by slicing 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        for idx in range(chunk_no, len(chunks)): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            id, s, csize = chunks[idx] 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             if s < offset: 
														 | 
														
														 | 
														
															             if s < offset: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															                 offset -= s 
														 | 
														
														 | 
														
															                 offset -= s 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                chunk_offset += s 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                chunk_no += 1 
														 | 
													
												
											
												
													
														| 
														 | 
														
															                 continue 
														 | 
														
														 | 
														
															                 continue 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             n = min(size, s - offset) 
														 | 
														
														 | 
														
															             n = min(size, s - offset) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             if id in self.data_cache: 
														 | 
														
														 | 
														
															             if id in self.data_cache: 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -622,6 +652,10 @@ class FuseOperations(llfuse.Operations): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             offset = 0 
														 | 
														
														 | 
														
															             offset = 0 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             size -= n 
														 | 
														
														 | 
														
															             size -= n 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             if not size: 
														 | 
														
														 | 
														
															             if not size: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                if fh in self._last_pos: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                    self._last_pos.upd(fh, (chunk_no, chunk_offset)) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                else: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                    self._last_pos[fh] = (chunk_no, chunk_offset) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															                 break 
														 | 
														
														 | 
														
															                 break 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         return b''.join(parts) 
														 | 
														
														 | 
														
															         return b''.join(parts) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 |