lib/perobs/SpaceTree.rb in perobs-3.0.1 vs lib/perobs/SpaceTree.rb in perobs-3.0.2

- old
+ new

@@ -38,44 +38,59 @@ # nodes can link to other nodes with smaller spaces, same spaces and bigger # spaces. The advantage of the ternary tree is that all nodes have equal # size which drastically simplifies the backing store operation. class SpaceTree - attr_reader :nodes + attr_reader :nodes, :cache # Manage the free spaces tree in the specified directory # @param dir [String] directory path of an existing directory def initialize(dir) @dir = dir # This EquiBlobsFile contains the nodes of the SpaceTree. @nodes = EquiBlobsFile.new(@dir, 'database_spaces', SpaceTreeNode::NODE_BYTES, 1) - @node_cache = SpaceTreeNodeCache.new(128) + @cache = SpaceTreeNodeCache.new(self, 128) end # Open the SpaceTree file. def open @nodes.open - @node_cache.clear - @root = SpaceTreeNode.new(self, nil, @nodes.total_entries == 0 ? - nil : @nodes.first_entry) - @node_cache.insert(@root) + @cache.clear + node = @nodes.total_entries == 0 ? + SpaceTreeNode::create(self) : + SpaceTreeNode::load(self, @nodes.first_entry) + @root_address = node.node_address end # Close the SpaceTree file. def close + @cache.flush @nodes.close - @root = nil - @node_cache.clear + @root_address = nil + @cache.clear end + # Flush all pending writes to the file system. + def sync + @cache.flush + @nodes.sync + end + + # Set a new root node for the SpaceTree + # @param node [SpaceTreeNode] def set_root(node) - @root = node + @root_address = node.node_address + @nodes.first_entry = node.node_address end + # Return the SpaceTreeNode that is the root of the SpaceTree. + def root + @root_address ? @cache.get(@root_address) : nil + end # Erase the SpaceTree file. This method cannot be called while the file is # open. def erase @nodes.erase @@ -86,94 +101,84 @@ # @param size [Integer] size of the space in bytes def add_space(address, size) if size <= 0 PEROBS.log.fatal "Size (#{size}) must be larger than 0." end - @root.add_space(address, size) + if has_space?(address, size) + PEROBS.log.fatal "The space with address #{address} and size #{size} " + + "can't be added twice." + end + root.add_space(address, size) end # Get a space that has at least the requested size. # @param size [Integer] Required size in bytes # @return [Array] Touple with address and actual size of the space. def get_space(size) if size <= 0 PEROBS.log.fatal "Size (#{size}) must be larger than 0." end - if (address_size = @root.find_matching_space(size)) + if (address_size = root.find_matching_space(size)) # First we try to find an exact match. return address_size - elsif (address_size = @root.find_equal_or_larger_space(size)) + elsif (address_size = root.find_equal_or_larger_space(size)) return address_size else return nil end end # Delete the node at the given address in the SpaceTree file. # @param address [Integer] address in file def delete_node(address) - @node_cache.delete(address) + @cache.delete(address) @nodes.delete_blob(address) end # Clear all pools and forget any registered spaces. def clear @nodes.clear - @node_cache.clear - @root = SpaceTreeNode.new(self) - @node_cache.insert(@root) + @cache.clear + @root_address = SpaceTreeNode::create(self).node_address end - # Create a new SpaceTreeNode. - # @param parent [SpaceTreeNode] parent node - # @param blob_address [Integer] address of the free space - # @param size [Integer] size of the free space - def new_node(parent, blob_address, size) - node = SpaceTreeNode.new(self, parent, nil, blob_address, size) - @node_cache.insert(node) - end - - # Return the SpaceTreeNode that matches the given node address. If a blob - # address and size are given, a new node is created instead of being read - # from the file. - # @param node_address [Integer] Address of the node in the SpaceTree file - # @return [SpaceTreeNode] - def get_node(node_address) - if (node = @node_cache.get(node_address)) - return node - end - - @node_cache.insert(SpaceTreeNode.new(self, nil, node_address)) - end - # Check if there is a space in the free space lists that matches the # address and the size. # @param [Integer] address Address of the space # @param [Integer] size Length of the space in bytes # @return [Boolean] True if space is found, false otherwise def has_space?(address, size) - @root.has_space?(address, size) + root.has_space?(address, size) end # Check if the index is OK and matches the flat_file data (if given). # @param flat_file [FlatFile] Flat file to compare with # @return True if space list matches, flase otherwise def check(flat_file = nil) @nodes.check - @root.check(flat_file) + root.check(flat_file) end + # Iterate over all entries and yield address and size. + def each + root.each do |node, mode, stack| + if mode == :on_enter + yield(node.blob_address, node.size) + end + end + end + # Complete internal tree data structure as textual tree. # @return [String] def to_s - @root.to_tree_s + root.to_tree_s end # Convert the tree into an Array of [address, size] touples. # @return [Array] def to_a - @root.to_a + root.to_a end end end