perobs 4.0.0 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +27 -16
  3. data/lib/perobs/Array.rb +66 -19
  4. data/lib/perobs/BTree.rb +106 -15
  5. data/lib/perobs/BTreeBlob.rb +4 -3
  6. data/lib/perobs/BTreeDB.rb +5 -4
  7. data/lib/perobs/BTreeNode.rb +482 -156
  8. data/lib/perobs/BTreeNodeLink.rb +10 -0
  9. data/lib/perobs/BigArray.rb +285 -0
  10. data/lib/perobs/BigArrayNode.rb +1002 -0
  11. data/lib/perobs/BigHash.rb +246 -0
  12. data/lib/perobs/BigTree.rb +197 -0
  13. data/lib/perobs/BigTreeNode.rb +873 -0
  14. data/lib/perobs/Cache.rb +48 -10
  15. data/lib/perobs/ConsoleProgressMeter.rb +61 -0
  16. data/lib/perobs/DataBase.rb +4 -3
  17. data/lib/perobs/DynamoDB.rb +57 -15
  18. data/lib/perobs/EquiBlobsFile.rb +155 -50
  19. data/lib/perobs/FNV_Hash_1a_64.rb +54 -0
  20. data/lib/perobs/FlatFile.rb +519 -227
  21. data/lib/perobs/FlatFileBlobHeader.rb +113 -54
  22. data/lib/perobs/FlatFileDB.rb +49 -23
  23. data/lib/perobs/FuzzyStringMatcher.rb +175 -0
  24. data/lib/perobs/Hash.rb +127 -33
  25. data/lib/perobs/IDList.rb +144 -0
  26. data/lib/perobs/IDListPage.rb +107 -0
  27. data/lib/perobs/IDListPageFile.rb +180 -0
  28. data/lib/perobs/IDListPageRecord.rb +142 -0
  29. data/lib/perobs/Object.rb +18 -15
  30. data/lib/perobs/ObjectBase.rb +46 -5
  31. data/lib/perobs/PersistentObjectCache.rb +57 -68
  32. data/lib/perobs/PersistentObjectCacheLine.rb +24 -12
  33. data/lib/perobs/ProgressMeter.rb +97 -0
  34. data/lib/perobs/SpaceManager.rb +273 -0
  35. data/lib/perobs/SpaceTree.rb +21 -12
  36. data/lib/perobs/SpaceTreeNode.rb +53 -61
  37. data/lib/perobs/Store.rb +264 -145
  38. data/lib/perobs/version.rb +1 -1
  39. data/lib/perobs.rb +2 -0
  40. data/perobs.gemspec +4 -4
  41. data/test/Array_spec.rb +15 -6
  42. data/test/BTree_spec.rb +6 -2
  43. data/test/BigArray_spec.rb +261 -0
  44. data/test/BigHash_spec.rb +152 -0
  45. data/test/BigTreeNode_spec.rb +153 -0
  46. data/test/BigTree_spec.rb +259 -0
  47. data/test/EquiBlobsFile_spec.rb +105 -1
  48. data/test/FNV_Hash_1a_64_spec.rb +59 -0
  49. data/test/FlatFileDB_spec.rb +198 -14
  50. data/test/FuzzyStringMatcher_spec.rb +261 -0
  51. data/test/Hash_spec.rb +13 -3
  52. data/test/IDList_spec.rb +77 -0
  53. data/test/LegacyDBs/LegacyDB.rb +155 -0
  54. data/test/LegacyDBs/version_3/class_map.json +1 -0
  55. data/test/LegacyDBs/version_3/config.json +1 -0
  56. data/test/LegacyDBs/version_3/database.blobs +0 -0
  57. data/test/LegacyDBs/version_3/database_spaces.blobs +0 -0
  58. data/test/LegacyDBs/version_3/index.blobs +0 -0
  59. data/test/LegacyDBs/version_3/version +1 -0
  60. data/test/LockFile_spec.rb +9 -6
  61. data/test/SpaceManager_spec.rb +176 -0
  62. data/test/SpaceTree_spec.rb +4 -1
  63. data/test/Store_spec.rb +305 -203
  64. data/test/spec_helper.rb +9 -4
  65. metadata +57 -16
  66. data/lib/perobs/BTreeNodeCache.rb +0 -109
  67. data/lib/perobs/TreeDB.rb +0 -277
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a988f009b1b97bc8da2b2bcfeb65399284a07032
4
- data.tar.gz: 4346d5cdbec5b4154741f0a41d3f526985803912
2
+ SHA256:
3
+ metadata.gz: c2c526c97aab15c09f8e8acbcb432203e7d60fef8c504df6ddb0b8f35459cca0
4
+ data.tar.gz: ad077bb879c041289c7a474e87645064ff84203c674640aff59b5f23923ac1b7
5
5
  SHA512:
6
- metadata.gz: 639673c10faa5082c742258ee9848f5e951c6d1ec7fc9f03ec7066260ea5042b6c8b90020df6fa506b8be54cc5fd9793a0939f80ef1da726c27832c8a2eb8c85
7
- data.tar.gz: 92e63145a1fc9b6e76dbdf6f4cdebfb5a8935bfcbd93a9634e22c12f874b945b656a17fe93aa03a7a3189a00371d2e2abd8d411862ad0ad51b0c364f7b7dc027
6
+ metadata.gz: b86fc662ef8bbf623ee7da777f023a74e3db9502df18c45dcda9ce244982225aaec7e74ce25378147c807775765c57d801810ac16be01d2145227bb0642caa3b
7
+ data.tar.gz: d0c5a79eb60a1221bc385a1fafbc77a1aaa1e47782b3ea27ca92f5f7c539804bc00a388fdddc1ab956d7805dbdd52d055f5cdd76a8bb155ec5ada4335b7b9175
data/README.md CHANGED
@@ -6,11 +6,12 @@ them from PEROBS::Object. They will be in memory when needed and
6
6
  transparently stored into a persistent storage.
7
7
 
8
8
  This library is ideal for Ruby applications that work on huge, mostly
9
- constant data sets and usually handle a small subset of the data at a
9
+ static data sets and usually process a small subset of the data at a
10
10
  time. To ensure data consistency of a larger data set, you can use
11
11
  transactions to make modifications of multiple objects atomicaly.
12
12
  Transactions can be nested and are aborted when an exception is
13
- raised.
13
+ raised. PEROBS is thread-safe, so you can use it in a multi-threaded
14
+ application.
14
15
 
15
16
  ## Usage
16
17
 
@@ -108,7 +109,7 @@ class Person < PEROBS::Object
108
109
  attr_init(:father) do { @store.new(Person, 'Dad') }
109
110
  end
110
111
 
111
- def merry(spouse)
112
+ def marry(spouse)
112
113
  self.spouse = spouse
113
114
  self.status = :married
114
115
  end
@@ -120,15 +121,18 @@ class Person < PEROBS::Object
120
121
 
121
122
  end
122
123
 
123
- store = PEROBS::Store.new('family')
124
- store['grandpa'] = joe = store.new(Person, 'Joe')
125
- store['grandma'] = jane = store.new(Person, 'Jane')
126
- jim = store.new(Person, 'Jim')
127
- jim.father = joe
128
- joe.kids << jim
129
- jim.mother = jane
130
- jane.kids << jim
131
- store.exit
124
+ begin
125
+ store = PEROBS::Store.new('family')
126
+ store['grandpa'] = joe = store.new(Person, 'Joe')
127
+ store['grandma'] = jane = store.new(Person, 'Jane')
128
+ jim = store.new(Person, 'Jim')
129
+ jim.father = joe
130
+ joe.kids << jim
131
+ jim.mother = jane
132
+ jane.kids << jim
133
+ ensure
134
+ store.exit
135
+ end
132
136
  ```
133
137
 
134
138
  When you run this script, a folder named 'family' will be created. It
@@ -166,9 +170,15 @@ object to another object.
166
170
 
167
171
  ### Caveats and known issues
168
172
 
169
- PEROBS is currently not thread-safe. You cannot simultaneously access
170
- the database from multiple application. The library uses locks to
171
- ensure that only one Store object is accessing the database at a time.
173
+ You cannot simultaneously access the database from multiple
174
+ applications concurrently. The library uses locks to ensure that only
175
+ one Store object is accessing the database at a time.
176
+
177
+ In case the application terminates without calling Store::exit(), the
178
+ database or the database index could get corrupted. To check the
179
+ consistency of your database you can use Store::check(). To check and
180
+ repair the database you can call Store::repair(). Depending on the
181
+ size of your database, these operations can last minutes to hours.
172
182
 
173
183
  ## Installation
174
184
 
@@ -188,7 +198,8 @@ Or install it yourself as:
188
198
 
189
199
  ## Copyright and License
190
200
 
191
- Copyright (c) 2015, 2016, 2017 by Chris Schlaeger <chris@taskjuggler.org>
201
+ Copyright (c) 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 by
202
+ Chris Schlaeger <chris@taskjuggler.org>
192
203
 
193
204
  PEROBS and all accompanying files are licensed under this MIT License
194
205
 
data/lib/perobs/Array.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # = Array.rb -- Persistent Ruby Object Store
4
4
  #
5
- # Copyright (c) 2015, 2016 by Chris Schlaeger <chris@taskjuggler.org>
5
+ # Copyright (c) 2015, 2016, 2017 by Chris Schlaeger <chris@taskjuggler.org>
6
6
  #
7
7
  # MIT License
8
8
  #
@@ -44,19 +44,27 @@ module PEROBS
44
44
 
45
45
  attr_reader :data
46
46
 
47
- # These methods do not mutate the Array. They only perform read
48
- # operations.
47
+ # These methods do not mutate the Array but create a new PEROBS::Array
48
+ # object. They only perform read operations.
49
49
  ([
50
- :&, :*, :+, :-, :==, :[], :<=>, :at, :abbrev, :assoc, :bsearch, :collect,
51
- :combination, :compact, :count, :cycle, :dclone, :drop, :drop_while,
50
+ :|, :&, :+, :-, :collect, :compact, :drop, :drop_while,
51
+ :flatten, :map, :reject, :reverse, :rotate, :select, :shuffle, :slice,
52
+ :sort, :take, :take_while, :uniq, :values_at
53
+ ] + Enumerable.instance_methods).uniq.each do |method_sym|
54
+ define_method(method_sym) do |*args, &block|
55
+ @store.cache.cache_read(self)
56
+ @store.new(PEROBS::Array, @data.send(method_sym, *args, &block))
57
+ end
58
+ end
59
+
60
+ # These methods do not mutate the Array and only perform read operations.
61
+ # They do not return basic objects types.
62
+ ([
63
+ :==, :[], :<=>, :at, :bsearch, :bsearch_index, :count, :cycle,
52
64
  :each, :each_index, :empty?, :eql?, :fetch, :find_index, :first,
53
- :flatten, :frozen?, :hash, :include?, :index, :join, :last,
54
- :length, :map, :pack, :permutation, :pretty_print, :pretty_print_cycle,
55
- :product, :rassoc, :reject, :repeated_combination,
56
- :repeated_permutation, :reverse, :reverse_each, :rindex, :rotate,
57
- :sample, :select, :shelljoin, :shuffle, :size, :slice, :sort, :take,
58
- :take_while, :to_a, :to_ary, :to_s, :transpose, :uniq, :values_at, :zip,
59
- :|
65
+ :frozen?, :include?, :index, :join, :last, :length, :pack,
66
+ :pretty_print, :pretty_print_cycle, :reverse_each, :rindex, :sample,
67
+ :size, :to_a, :to_ary, :to_s
60
68
  ] + Enumerable.instance_methods).uniq.each do |method_sym|
61
69
  define_method(method_sym) do |*args, &block|
62
70
  @store.cache.cache_read(self)
@@ -64,12 +72,23 @@ module PEROBS
64
72
  end
65
73
  end
66
74
 
75
+ # These methods mutate the Array and return self.
76
+ [
77
+ :<<, :clear, :collect!, :compact!, :concat,
78
+ :fill, :flatten!, :insert, :keep_if, :map!, :push,
79
+ :reject!, :replace, :select!, :reverse!, :rotate!, :shuffle!,
80
+ :slice!, :sort!, :sort_by!, :uniq!
81
+ ].each do |method_sym|
82
+ define_method(method_sym) do |*args, &block|
83
+ @store.cache.cache_write(self)
84
+ @data.send(method_sym, *args, &block)
85
+ myself
86
+ end
87
+ end
88
+
67
89
  # These methods mutate the Array.
68
90
  [
69
- :<<, :[]=, :clear, :collect!, :compact!, :concat, :delete, :delete_at,
70
- :delete_if, :fill, :flatten!, :insert, :keep_if, :map!, :pop, :push,
71
- :reject!, :replace, :select!, :reverse!, :rotate!, :shift, :shuffle!,
72
- :slice!, :sort!, :sort_by!, :uniq!, :unshift
91
+ :delete, :delete_at, :delete_if, :shift, :pop
73
92
  ].each do |method_sym|
74
93
  define_method(method_sym) do |*args, &block|
75
94
  @store.cache.cache_write(self)
@@ -81,17 +100,45 @@ module PEROBS
81
100
  # PEROBS users should never call this method or equivalents of derived
82
101
  # methods directly.
83
102
  # @param p [PEROBS::Handle] PEROBS handle
84
- # @param size [Integer] The requested size of the Array
103
+ # @param arg1 [Integer or Array] The requested size of the Array or an
104
+ # Array to initialize
85
105
  # @param default [Any] The default value that is returned when no value is
86
106
  # stored for a specific key.
87
- def initialize(p, size = 0, default = nil)
107
+ def initialize(p, arg1 = 0, default = nil, &block)
88
108
  super(p)
89
- @data = ::Array.new(size, default)
109
+ if arg1.is_a?(::Array)
110
+ arg1.each { |v| _check_assignment_value(v) }
111
+ @data = arg1.dup
112
+ elsif block_given?
113
+ @data = ::Array.new(arg1) do
114
+ _check_assignment_value(yield)
115
+ end
116
+ else
117
+ @data = ::Array.new(arg1, _check_assignment_value(default))
118
+ end
90
119
 
91
120
  # Ensure that the newly created object will be pushed into the database.
92
121
  @store.cache.cache_write(self)
93
122
  end
94
123
 
124
+ # Proxy for the assignment method.
125
+ def []=(*args)
126
+ if (args.length == 2)
127
+ _check_assignment_value(args[1])
128
+ else
129
+ _check_assignment_value(args[2])
130
+ end
131
+ @store.cache.cache_write(self)
132
+ @data.[]=(*args)
133
+ end
134
+
135
+ # Proxy for the unshift method.
136
+ def unshift(val)
137
+ _check_assignment_value(val)
138
+ @store.cache.cache_write(self)
139
+ @data.unshift(val)
140
+ end
141
+
95
142
  # Return a list of all object IDs of all persistend objects that this Array
96
143
  # is referencing.
97
144
  # @return [Array of Integer] IDs of referenced objects
data/lib/perobs/BTree.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # = BTreeNode.rb -- Persistent Ruby Object Store
4
4
  #
5
- # Copyright (c) 2016, 2017 by Chris Schlaeger <chris@taskjuggler.org>
5
+ # Copyright (c) 2016, 2017, 2018 by Chris Schlaeger <chris@taskjuggler.org>
6
6
  #
7
7
  # MIT License
8
8
  #
@@ -32,7 +32,7 @@ require 'perobs/BTreeNode'
32
32
 
33
33
  module PEROBS
34
34
 
35
- # This BTree class is very similar to a classic BTree implementation. It
35
+ # This BTree class is very similar to a classic B+Tree implementation. It
36
36
  # manages a tree that is always balanced. The BTree is stored in the
37
37
  # specified directory and partially kept in memory to speed up operations.
38
38
  # The order of the tree specifies how many keys each node will be able to
@@ -40,18 +40,21 @@ module PEROBS
40
40
  # have N + 1 references to child nodes instead.
41
41
  class BTree
42
42
 
43
- attr_reader :order, :nodes, :node_cache
43
+ attr_reader :order, :nodes, :node_cache, :first_leaf, :last_leaf, :size
44
44
 
45
45
  # Create a new BTree object.
46
46
  # @param dir [String] Directory to store the tree file
47
47
  # @param name [String] Base name of the BTree related files in 'dir'
48
48
  # @param order [Integer] The maximum number of keys per node. This number
49
49
  # must be odd and larger than 2 and smaller than 2**16 - 1.
50
- def initialize(dir, name, order)
50
+ # @param progressmeter [ProgressMeter] reference to a ProgressMeter object
51
+ def initialize(dir, name, order, progressmeter)
51
52
  @dir = dir
52
53
  @name = name
53
- unless order > 2
54
- PEROBS.log.fatal "BTree order must be larger than 2, not #{order}"
54
+ @progressmeter = progressmeter
55
+
56
+ unless order > 4
57
+ PEROBS.log.fatal "BTree order must be larger than 4, not #{order}"
55
58
  end
56
59
  unless order % 2 == 1
57
60
  PEROBS.log.fatal "BTree order must be an uneven number, not #{order}"
@@ -62,9 +65,14 @@ module PEROBS
62
65
  @order = order
63
66
 
64
67
  # This EquiBlobsFile contains the nodes of the BTree.
65
- @nodes = EquiBlobsFile.new(@dir, @name,
68
+ @nodes = EquiBlobsFile.new(@dir, @name, @progressmeter,
66
69
  BTreeNode::node_bytes(@order))
67
- @node_cache = PersistentObjectCache.new(512, BTreeNode, self)
70
+ @nodes.register_custom_data('first_leaf')
71
+ @nodes.register_custom_data('last_leaf')
72
+ @nodes.register_custom_data('btree_size')
73
+ @node_cache = PersistentObjectCache.new(2**13, 2**13, BTreeNode, self)
74
+ @root = @first_leaf = @last_leaf = nil
75
+ @size = 0
68
76
 
69
77
  # This BTree implementation uses a write cache to improve write
70
78
  # performance of multiple successive read/write operations. This also
@@ -89,23 +97,44 @@ module PEROBS
89
97
 
90
98
  @node_cache.clear
91
99
  @nodes.open
92
- node = @nodes.total_entries == 0 ?
93
- BTreeNode::create(self) :
94
- BTreeNode::load(self, @nodes.first_entry)
100
+
101
+ if @nodes.total_entries == 0
102
+ # We've created a new nodes file
103
+ node = BTreeNode::create(self)
104
+ else
105
+ # We are loading an existing tree.
106
+ node = BTreeNode::load_and_link(self, @nodes.first_entry)
107
+ @first_leaf = BTreeNode::load_and_link(
108
+ self, @nodes.get_custom_data('first_leaf'))
109
+ @last_leaf = BTreeNode::load_and_link(
110
+ self, @nodes.get_custom_data('last_leaf'))
111
+ end
95
112
  set_root(node)
113
+
114
+ # Get the total number of entries that are stored in the tree.
115
+ @size = @nodes.get_custom_data('btree_size')
96
116
  end
97
117
 
98
118
  # Close the tree file.
99
119
  def close
100
120
  sync
121
+ PEROBS.log.info "BTree file #{@name} has currently " +
122
+ "#{@nodes.total_entries} used entries and #{@nodes.total_spaces} " +
123
+ "unused entries"
101
124
  @nodes.close
102
125
  @root = nil
103
126
  end
104
127
 
128
+ # @return true if file is currently open
129
+ def is_open?
130
+ !@root.nil?
131
+ end
132
+
105
133
  # Clear all pools and forget any registered spaces.
106
134
  def clear
107
135
  @node_cache.clear
108
136
  @nodes.clear
137
+ @size = 0
109
138
  set_root(BTreeNode::create(self))
110
139
  end
111
140
 
@@ -114,6 +143,7 @@ module PEROBS
114
143
  # all stored data from the BTree.
115
144
  def erase
116
145
  @nodes.erase
146
+ @size = 0
117
147
  @root = nil
118
148
  @dirty_flag.forced_unlock
119
149
  end
@@ -121,6 +151,7 @@ module PEROBS
121
151
  # Flush all pending modifications into the tree file.
122
152
  def sync
123
153
  @node_cache.flush(true)
154
+ @nodes.set_custom_data('btree_size', @size)
124
155
  @nodes.sync
125
156
  @dirty_flag.unlock if @dirty_flag.is_locked?
126
157
  end
@@ -128,22 +159,70 @@ module PEROBS
128
159
  # Check if the tree file contains any errors.
129
160
  # @return [Boolean] true if no erros were found, false otherwise
130
161
  def check(&block)
131
- @root.check(&block)
162
+ sync
163
+ return false unless @nodes.check
164
+
165
+ entries = 0
166
+ stats = nil
167
+ @progressmeter.start('Checking index structure', @size) do |pm|
168
+ stats = @root.check do |k, v|
169
+ pm.update(entries += 1)
170
+ block_given? ? yield(k, v) : true
171
+ end
172
+ end
173
+
174
+ return false unless stats
175
+
176
+ unless entries == @size
177
+ PEROBS.log.error "The BTree size (#{@size}) and the number of " +
178
+ "found entries (#{entries}) don't match"
179
+ return false
180
+ end
181
+ unless stats.nodes_count == @nodes.total_entries
182
+ PEROBS.log.error "The BTree nodes count (#{stats.nodes_count}) and " +
183
+ "the number of entries in the nodes file (#{@nodes.total_entries}) " +
184
+ "don't match"
185
+ return false
186
+ end
187
+ PEROBS.log.info "Statistics for the BTree #{@name}: " +
188
+ "Number of nodes: #{stats.nodes_count}; " +
189
+ "Branch depth: #{stats.branch_depth}; " +
190
+ "Number of leave nodes: #{stats.leave_nodes}; " +
191
+ "Number of leaves: #{stats.leaves}"
192
+
193
+ true
132
194
  end
133
195
 
134
196
  # Register a new node as root node of the tree.
197
+ # @param node [BTreeNode]
135
198
  def set_root(node)
136
199
  @root = node
137
200
  @nodes.first_entry = node.node_address
138
201
  end
139
202
 
203
+ # Set the address of the first leaf node.
204
+ # @param node [BTreeNode]
205
+ def set_first_leaf(node)
206
+ @first_leaf = node
207
+ @nodes.set_custom_data('first_leaf', node.node_address)
208
+ end
209
+
210
+ # Set the address of the last leaf node.
211
+ # @param node [BTreeNode]
212
+ def set_last_leaf(node)
213
+ @last_leaf = node
214
+ @nodes.set_custom_data('last_leaf', node.node_address)
215
+ end
216
+
140
217
  # Insert a new value into the tree using the key as a unique index. If the
141
218
  # key already exists the old value will be overwritten.
142
219
  # @param key [Integer] Unique key
143
220
  # @param value [Integer] value
144
221
  def insert(key, value)
145
- @root.insert(key, value)
146
- @node_cache.flush
222
+ if @root.insert(key, value)
223
+ @size += 1
224
+ @node_cache.flush
225
+ end
147
226
  end
148
227
 
149
228
  # Retrieve the value associated with the given key. If no entry was found,
@@ -154,10 +233,17 @@ module PEROBS
154
233
  @root.get(key)
155
234
  end
156
235
 
236
+ # Either return the key/value pair that exactly matches the key or a
237
+ # key/value pair that has a key that is at least min_miss_increment larger
238
+ # than the key.
239
+ def get_best_match(key, min_miss_increment)
240
+ @root.get_best_match(key, min_miss_increment)
241
+ end
242
+
157
243
  # Find and remove the value associated with the given key. If no entry was
158
244
  # found, return nil, otherwise the found value.
159
245
  def remove(key)
160
- removed_value = @root.remove(key)
246
+ @size -= 1 unless (removed_value = @root.remove(key)).nil?
161
247
 
162
248
  # Check if the root node only contains one child link after the delete
163
249
  # operation. Then we can delete that node and pull the tree one level
@@ -187,6 +273,11 @@ module PEROBS
187
273
  @nodes.delete_blob(address)
188
274
  end
189
275
 
276
+ # @return [Integer] The number of entries stored in the tree.
277
+ def entries_count
278
+ @size
279
+ end
280
+
190
281
  # @return [String] Human reable form of the tree.
191
282
  def to_s
192
283
  @root.to_s
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # = BTreeBlob.rb -- Persistent Ruby Object Store
4
4
  #
5
- # Copyright (c) 2015, 2016 by Chris Schlaeger <chris@taskjuggler.org>
5
+ # Copyright (c) 2015, 2016, 2019 by Chris Schlaeger <chris@taskjuggler.org>
6
6
  #
7
7
  # MIT License
8
8
  #
@@ -33,7 +33,7 @@ require 'perobs/RobustFile'
33
33
  module PEROBS
34
34
 
35
35
  # This class manages the usage of the data blobs in the corresponding
36
- # HashedBlobsDB object.
36
+ # BTreeDB object.
37
37
  class BTreeBlob
38
38
 
39
39
  # Magic number used for index files.
@@ -144,11 +144,12 @@ module PEROBS
144
144
 
145
145
  # Remove all entries from the index that have not been marked.
146
146
  # @return [Array] List of deleted object IDs.
147
- def delete_unmarked_entries
147
+ def delete_unmarked_entries(&block)
148
148
  deleted_ids = []
149
149
  # First remove the entry from the hash table.
150
150
  @entries_by_id.delete_if do |id, e|
151
151
  if e[MARKED] == 0
152
+ yield(id) if block_given?
152
153
  deleted_ids << id
153
154
  true
154
155
  else
@@ -2,7 +2,8 @@
2
2
  #
3
3
  # = BTreeDB.rb -- Persistent Ruby Object Store
4
4
  #
5
- # Copyright (c) 2015, 2016 by Chris Schlaeger <chris@taskjuggler.org>
5
+ # Copyright (c) 2015, 2016, 2018, 2019
6
+ # by Chris Schlaeger <chris@taskjuggler.org>
6
7
  #
7
8
  # MIT License
8
9
  #
@@ -58,7 +59,7 @@ module PEROBS
58
59
  # nodes. The insert/find/delete time grows
59
60
  # linearly with the size.
60
61
  def initialize(db_name, options = {})
61
- super(options[:serializer] || :json)
62
+ super(options)
62
63
 
63
64
  @db_dir = db_name
64
65
  # Create the database directory if it doesn't exist yet.
@@ -159,9 +160,9 @@ module PEROBS
159
160
  # Permanently delete all objects that have not been marked. Those are
160
161
  # orphaned and are no longer referenced by any actively used object.
161
162
  # @return [Array] List of IDs that have been removed from the DB.
162
- def delete_unmarked_objects
163
+ def delete_unmarked_objects(&block)
163
164
  deleted_ids = []
164
- each_blob { |blob| deleted_ids += blob.delete_unmarked_entries }
165
+ each_blob { |blob| deleted_ids += blob.delete_unmarked_entries(&block) }
165
166
  deleted_ids
166
167
  end
167
168