Class: PEROBS::FreeSpaceManager

Inherits:
Object
  • Object
show all
Defined in:
lib/perobs/FreeSpaceManager.rb

Overview

The FreeSpaceManager keeps a list of the free spaces in the FlatFile. Each space is stored with address and size. The data is persisted in the file system. Internally the free spaces are stored in different pools. Each pool holds spaces that are at least of a given size and not as big as the next pool up. Pool entry minimum sizes increase by a factor of 2 from pool to pool.

Instance Method Summary collapse

Constructor Details

#initialize(dir) ⇒ FreeSpaceManager

Create a new FreeSpaceManager object in the specified directory.

Parameters:

  • dir (String)

    directory path



43
44
45
46
# File 'lib/perobs/FreeSpaceManager.rb', line 43

def initialize(dir)
  @dir = dir
  @pools = []
end

Instance Method Details

#add_space(address, size) ⇒ Object

Add a new space with a given address and size.

Parameters:

  • address (Integer)

    Starting address of the space

  • size (Integer)

    size of the space in bytes



66
67
68
69
70
71
72
73
# File 'lib/perobs/FreeSpaceManager.rb', line 66

def add_space(address, size)
  if size <= 0
    PEROBS.log.fatal "Size (#{size}) must be larger than 0."
  end
  pool_index = msb(size)
  new_pool(pool_index) unless @pools[pool_index]
  push_pool(pool_index, [ address, size ].pack('QQ'))
end

#check(flat_file) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/perobs/FreeSpaceManager.rb', line 138

def check(flat_file)
  @pools.each do |pool|
    next unless pool

    pool.open
    pool.each do |entry|
      address, size = entry.unpack('QQ')
      unless flat_file.has_space?(address, size)
        PEROBS.log.error "FreeSpaceManager has space that isn't " +
          "available in the FlatFile."
        return false
      end
    end
    pool.close
  end

  true
end

#clearObject

Clear all pools and forget any registered spaces.



100
101
102
103
104
105
106
107
108
109
# File 'lib/perobs/FreeSpaceManager.rb', line 100

def clear
  @pools.each do |pool|
    if pool
      pool.open
      pool.clear
      pool.close
    end
  end
  close
end

#closeObject

Close all pool files.



59
60
61
# File 'lib/perobs/FreeSpaceManager.rb', line 59

def close
  @pools = []
end

#get_space(size) ⇒ Array

Get a space that has at least the requested size.

Parameters:

  • size (Integer)

    Required size in bytes

Returns:

  • (Array)

    Touple with address and actual size of the space.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/perobs/FreeSpaceManager.rb', line 78

def get_space(size)
  if size <= 0
    PEROBS.log.fatal "Size (#{size}) must be larger than 0."
  end
  # When we search for a free space we need to search the pool that
  # corresponds to (size - 1) * 2. It is the pool that has the spaces that
  # are at least as big as size.
  pool_index = size == 1 ? 0 : msb(size - 1) + 1
  unless @pools[pool_index]
    return nil
  else
    return nil unless (entry = pop_pool(pool_index))
    sp_address, sp_size = entry.unpack('QQ')
    if sp_size < size
      PEROBS.log.fatal "Space at address #{sp_address} is too small. " +
        "Must be at least #{size} bytes but is only #{sp_size} bytes."
    end
    [ sp_address, sp_size ]
  end
end

#has_space?(address, size) ⇒ Boolean

Check if there is a space in the free space lists that matches the address and the size.

Parameters:

  • address (Integer)

    Address of the space

  • size (Integer)

    Length of the space in bytes

Returns:

  • (Boolean)

    True if space is found, false otherwise



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/perobs/FreeSpaceManager.rb', line 116

def has_space?(address, size)
  unless (pool = @pools[msb(size)])
    return false
  end

  pool.open
  pool.each do |entry|
    sp_address, sp_size = entry.unpack('QQ')
    if address == sp_address
      if size != sp_size
        PEROBS.log.fatal "FreeSpaceManager has space with different " +
          "size"
      end
      pool.close
      return true
    end
  end

  pool.close
  false
end

#inspectObject



157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/perobs/FreeSpaceManager.rb', line 157

def inspect
  '[' + @pools.map do |p|
    if p
      p.open
      r = p.to_ary.map { |bs| bs.unpack('QQ')}.inspect
      p.close
      r
    else
      'nil'
    end
  end.join(', ') + ']'
end

#openObject

Open the pool files.



49
50
51
52
53
54
55
56
# File 'lib/perobs/FreeSpaceManager.rb', line 49

def open
  Dir.glob(File.join(@dir, 'free_list_*.stack')).each do |file|
    basename = File.basename(file)
    # Cut out the pool index from the file name.
    index = basename[10..-7].to_i
    @pools[index] = StackFile.new(@dir, basename[0..-7], 2 * 8)
  end
end