perobs 4.0.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
data/test/spec_helper.rb CHANGED
@@ -41,15 +41,20 @@ def generate_db_name(caller_file)
41
41
  end
42
42
 
43
43
  def capture_io
44
- PEROBS.log.open(io = StringIO.new)
44
+ old_stdout = $stdout
45
+ $stdout = out = StringIO.new
46
+ PEROBS.log.open(log = StringIO.new)
47
+
45
48
  begin
46
49
  yield
47
50
  ensure
51
+ $stdout = old_stdout
48
52
  PEROBS.log.open($stderr)
49
53
  end
50
54
 
51
- io.rewind
52
- io.read
53
- end
55
+ out.rewind
56
+ log.rewind
54
57
 
58
+ Struct.new(:out, :log).new(out.read, log.read)
59
+ end
55
60
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perobs
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 4.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Schlaeger
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-05 00:00:00.000000000 Z
11
+ date: 2022-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,42 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.6'
19
+ version: '2.3'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.6'
26
+ version: '2.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: yard
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.8.7
33
+ version: 0.9.12
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.8.7
40
+ version: 0.9.12
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: 13.0.3
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: 13.0.3
55
55
  description: Library to provide a persistent object store
56
56
  email:
57
57
  - chris@linux.com
@@ -70,31 +70,43 @@ files:
70
70
  - lib/perobs/BTreeBlob.rb
71
71
  - lib/perobs/BTreeDB.rb
72
72
  - lib/perobs/BTreeNode.rb
73
- - lib/perobs/BTreeNodeCache.rb
74
73
  - lib/perobs/BTreeNodeLink.rb
74
+ - lib/perobs/BigArray.rb
75
+ - lib/perobs/BigArrayNode.rb
76
+ - lib/perobs/BigHash.rb
77
+ - lib/perobs/BigTree.rb
78
+ - lib/perobs/BigTreeNode.rb
75
79
  - lib/perobs/Cache.rb
76
80
  - lib/perobs/ClassMap.rb
81
+ - lib/perobs/ConsoleProgressMeter.rb
77
82
  - lib/perobs/DataBase.rb
78
83
  - lib/perobs/DynamoDB.rb
79
84
  - lib/perobs/EquiBlobsFile.rb
85
+ - lib/perobs/FNV_Hash_1a_64.rb
80
86
  - lib/perobs/FlatFile.rb
81
87
  - lib/perobs/FlatFileBlobHeader.rb
82
88
  - lib/perobs/FlatFileDB.rb
89
+ - lib/perobs/FuzzyStringMatcher.rb
83
90
  - lib/perobs/Handle.rb
84
91
  - lib/perobs/Hash.rb
92
+ - lib/perobs/IDList.rb
93
+ - lib/perobs/IDListPage.rb
94
+ - lib/perobs/IDListPageFile.rb
95
+ - lib/perobs/IDListPageRecord.rb
85
96
  - lib/perobs/LockFile.rb
86
97
  - lib/perobs/Log.rb
87
98
  - lib/perobs/Object.rb
88
99
  - lib/perobs/ObjectBase.rb
89
100
  - lib/perobs/PersistentObjectCache.rb
90
101
  - lib/perobs/PersistentObjectCacheLine.rb
102
+ - lib/perobs/ProgressMeter.rb
91
103
  - lib/perobs/RobustFile.rb
104
+ - lib/perobs/SpaceManager.rb
92
105
  - lib/perobs/SpaceTree.rb
93
106
  - lib/perobs/SpaceTreeNode.rb
94
107
  - lib/perobs/SpaceTreeNodeLink.rb
95
108
  - lib/perobs/StackFile.rb
96
109
  - lib/perobs/Store.rb
97
- - lib/perobs/TreeDB.rb
98
110
  - lib/perobs/version.rb
99
111
  - perobs.gemspec
100
112
  - tasks/changelog.rake
@@ -104,12 +116,27 @@ files:
104
116
  - test/Array_spec.rb
105
117
  - test/BTreeDB_spec.rb
106
118
  - test/BTree_spec.rb
119
+ - test/BigArray_spec.rb
120
+ - test/BigHash_spec.rb
121
+ - test/BigTreeNode_spec.rb
122
+ - test/BigTree_spec.rb
107
123
  - test/ClassMap_spec.rb
108
124
  - test/EquiBlobsFile_spec.rb
125
+ - test/FNV_Hash_1a_64_spec.rb
109
126
  - test/FlatFileDB_spec.rb
127
+ - test/FuzzyStringMatcher_spec.rb
110
128
  - test/Hash_spec.rb
129
+ - test/IDList_spec.rb
130
+ - test/LegacyDBs/LegacyDB.rb
131
+ - test/LegacyDBs/version_3/class_map.json
132
+ - test/LegacyDBs/version_3/config.json
133
+ - test/LegacyDBs/version_3/database.blobs
134
+ - test/LegacyDBs/version_3/database_spaces.blobs
135
+ - test/LegacyDBs/version_3/index.blobs
136
+ - test/LegacyDBs/version_3/version
111
137
  - test/LockFile_spec.rb
112
138
  - test/Object_spec.rb
139
+ - test/SpaceManager_spec.rb
113
140
  - test/SpaceTree_spec.rb
114
141
  - test/StackFile_spec.rb
115
142
  - test/Store_spec.rb
@@ -119,7 +146,7 @@ homepage: https://github.com/scrapper/perobs
119
146
  licenses:
120
147
  - MIT
121
148
  metadata: {}
122
- post_install_message:
149
+ post_install_message:
123
150
  rdoc_options: []
124
151
  require_paths:
125
152
  - lib
@@ -127,28 +154,42 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
154
  requirements:
128
155
  - - ">="
129
156
  - !ruby/object:Gem::Version
130
- version: '2.0'
157
+ version: '2.4'
131
158
  required_rubygems_version: !ruby/object:Gem::Requirement
132
159
  requirements:
133
160
  - - ">="
134
161
  - !ruby/object:Gem::Version
135
162
  version: '0'
136
163
  requirements: []
137
- rubyforge_project:
138
- rubygems_version: 2.2.5
139
- signing_key:
164
+ rubygems_version: 3.2.32
165
+ signing_key:
140
166
  specification_version: 4
141
167
  summary: Persistent Ruby Object Store
142
168
  test_files:
143
169
  - test/Array_spec.rb
144
170
  - test/BTreeDB_spec.rb
145
171
  - test/BTree_spec.rb
172
+ - test/BigArray_spec.rb
173
+ - test/BigHash_spec.rb
174
+ - test/BigTreeNode_spec.rb
175
+ - test/BigTree_spec.rb
146
176
  - test/ClassMap_spec.rb
147
177
  - test/EquiBlobsFile_spec.rb
178
+ - test/FNV_Hash_1a_64_spec.rb
148
179
  - test/FlatFileDB_spec.rb
180
+ - test/FuzzyStringMatcher_spec.rb
149
181
  - test/Hash_spec.rb
182
+ - test/IDList_spec.rb
183
+ - test/LegacyDBs/LegacyDB.rb
184
+ - test/LegacyDBs/version_3/class_map.json
185
+ - test/LegacyDBs/version_3/config.json
186
+ - test/LegacyDBs/version_3/database.blobs
187
+ - test/LegacyDBs/version_3/database_spaces.blobs
188
+ - test/LegacyDBs/version_3/index.blobs
189
+ - test/LegacyDBs/version_3/version
150
190
  - test/LockFile_spec.rb
151
191
  - test/Object_spec.rb
192
+ - test/SpaceManager_spec.rb
152
193
  - test/SpaceTree_spec.rb
153
194
  - test/StackFile_spec.rb
154
195
  - test/Store_spec.rb
@@ -1,109 +0,0 @@
1
- # encoding: UTF-8
2
- #
3
- # = BTree.rb -- Persistent Ruby Object Store
4
- #
5
- # Copyright (c) 2016, 2017 by Chris Schlaeger <chris@taskjuggler.org>
6
- #
7
- # MIT License
8
- #
9
- # Permission is hereby granted, free of charge, to any person obtaining
10
- # a copy of this software and associated documentation files (the
11
- # "Software"), to deal in the Software without restriction, including
12
- # without limitation the rights to use, copy, modify, merge, publish,
13
- # distribute, sublicense, and/or sell copies of the Software, and to
14
- # permit persons to whom the Software is furnished to do so, subject to
15
- # the following conditions:
16
- #
17
- # The above copyright notice and this permission notice shall be
18
- # included in all copies or substantial portions of the Software.
19
- #
20
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
-
28
- require 'perobs/BTreeNode'
29
-
30
- module PEROBS
31
-
32
- class BTreeNodeCache
33
-
34
- def initialize(tree)
35
- @tree = tree
36
- clear
37
- end
38
-
39
- def get(address)
40
- if (node = @modified_nodes[address])
41
- return node
42
- end
43
-
44
- if (node = @top_nodes[address])
45
- return node
46
- end
47
-
48
- if (node = @ephemeral_nodes[address])
49
- return node
50
- end
51
-
52
- BTreeNode::load(@tree, address)
53
- end
54
-
55
- def set_root(node)
56
- node = node.get_node if node.is_a?(BTreeNodeLink)
57
-
58
- @top_nodes = {}
59
- @top_nodes[node.node_address] = node
60
- end
61
-
62
- def insert(node, modified = true)
63
- unless node
64
- PEROBS.log.fatal "nil cannot be cached"
65
- end
66
- node = node.get_node if node.is_a?(BTreeNodeLink)
67
-
68
- if modified
69
- @modified_nodes[node.node_address] = node
70
- end
71
- @ephemeral_nodes[node.node_address] = node
72
-
73
- if !@top_nodes.include?(node) && node.is_top?
74
- @top_nodes[node.node_address] = node
75
- end
76
- end
77
-
78
- def _collect(address, ruby_object_id)
79
- # Just a dummy for now
80
- end
81
-
82
- # Remove a node from the cache.
83
- # @param address [Integer] address of node to remove.
84
- def delete(address)
85
- @ephemeral_nodes.delete(address)
86
- @top_nodes.delete(address)
87
- @modified_nodes.delete(address)
88
- end
89
-
90
- # Flush all dirty nodes into the backing store.
91
- def flush(now = false)
92
- if now || @modified_nodes.size > 1024
93
- @modified_nodes.each_value { |node| node.write_node }
94
- @modified_nodes = {}
95
- end
96
- @ephemeral_nodes = {}
97
- end
98
-
99
- # Remove all nodes from the cache.
100
- def clear
101
- @top_nodes = {}
102
- @ephemeral_nodes = {}
103
- @modified_nodes = {}
104
- end
105
-
106
- end
107
-
108
- end
109
-
data/lib/perobs/TreeDB.rb DELETED
@@ -1,277 +0,0 @@
1
- # encoding: UTF-8
2
- #
3
- # = BTreeDB.rb -- Persistent Ruby Object Store
4
- #
5
- # Copyright (c) 2015, 2016 by Chris Schlaeger <chris@taskjuggler.org>
6
- #
7
- # MIT License
8
- #
9
- # Permission is hereby granted, free of charge, to any person obtaining
10
- # a copy of this software and associated documentation files (the
11
- # "Software"), to deal in the Software without restriction, including
12
- # without limitation the rights to use, copy, modify, merge, publish,
13
- # distribute, sublicense, and/or sell copies of the Software, and to
14
- # permit persons to whom the Software is furnished to do so, subject to
15
- # the following conditions:
16
- #
17
- # The above copyright notice and this permission notice shall be
18
- # included in all copies or substantial portions of the Software.
19
- #
20
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
-
28
- require 'fileutils'
29
-
30
- require 'perobs/Log'
31
- require 'perobs/RobustFile'
32
- require 'perobs/DataBase'
33
- require 'perobs/BTreeBlob'
34
-
35
- module PEROBS
36
-
37
- # This class implements a BTree database using filesystem directories as
38
- # nodes and blob files as leafs. The BTree grows with the number of stored
39
- # entries. Each leaf node blob can hold a fixed number of entries. If more
40
- # entries need to be stored, the blob is replaced by a node with multiple
41
- # new leafs that store the entries of the previous node. The leafs are
42
- # implemented by the BTreeBlob class.
43
- class BTreeDB < DataBase
44
-
45
- attr_reader :max_blob_size
46
-
47
- # Create a new BTreeDB object.
48
- # @param db_name [String] name of the DB directory
49
- # @param options [Hash] options to customize the behavior. Currently only
50
- # the following options are supported:
51
- # :serializer : Can be :marshal, :json, :yaml
52
- # :dir_bits : The number of bits to use for the BTree nodes.
53
- # The value must be between 4 and 14. The larger
54
- # the number the more back-end directories are
55
- # being used. The default is 12 which results in
56
- # 4096 directories per node.
57
- # :max_blob_size : The maximum number of entries in the BTree leaf
58
- # nodes. The insert/find/delete time grows
59
- # linearly with the size.
60
- def initialize(db_name, options = {})
61
- super(options[:serializer] || :json)
62
-
63
- @db_dir = db_name
64
- # Create the database directory if it doesn't exist yet.
65
- ensure_dir_exists(@db_dir)
66
-
67
- # Read the existing DB config.
68
- @config = get_hash('config')
69
- check_option('serializer')
70
-
71
- # Check and set @dir_bits, the number of bits used for each tree level.
72
- @dir_bits = options[:dir_bits] || 12
73
- if @dir_bits < 4 || @dir_bits > 14
74
- PEROBS.log.fatal "dir_bits option (#{@dir_bits}) must be between 4 " +
75
- "and 12"
76
- end
77
- check_option('dir_bits')
78
-
79
- @max_blob_size = options[:max_blob_size] || 32
80
- if @max_blob_size < 4 || @max_blob_size > 128
81
- PEROBS.log.fatal "max_blob_size option (#{@max_blob_size}) must be " +
82
- "between 4 and 128"
83
- end
84
- check_option('max_blob_size')
85
-
86
- put_hash('config', @config)
87
-
88
- # This format string is used to create the directory name.
89
- @dir_format_string = "%0#{(@dir_bits / 4) +
90
- (@dir_bits % 4 == 0 ? 0 : 1)}X"
91
- # Bit mask to extract the dir_bits LSBs.
92
- @dir_mask = 2 ** @dir_bits - 1
93
- end
94
-
95
- # Delete the entire database. The database is no longer usable after this
96
- # method was called.
97
- def delete_database
98
- FileUtils.rm_rf(@db_dir)
99
- end
100
-
101
- def BTreeDB::delete_db(db_name)
102
- FileUtils.rm_rf(db_name)
103
- end
104
-
105
- # Return true if the object with given ID exists
106
- # @param id [Integer]
107
- def include?(id)
108
- !(blob = find_blob(id)).nil? && !blob.find(id).nil?
109
- end
110
-
111
- # Store a simple Hash as a JSON encoded file into the DB directory.
112
- # @param name [String] Name of the hash. Will be used as file name.
113
- # @param hash [Hash] A Hash that maps String objects to strings or
114
- # numbers.
115
- def put_hash(name, hash)
116
- file_name = File.join(@db_dir, name + '.json')
117
- begin
118
- RobustFile.write(file_name, hash.to_json)
119
- rescue IOError => e
120
- PEROBS.log.fatal "Cannot write hash file '#{file_name}': #{e.message}"
121
- end
122
- end
123
-
124
- # Load the Hash with the given name.
125
- # @param name [String] Name of the hash.
126
- # @return [Hash] A Hash that maps String objects to strings or numbers.
127
- def get_hash(name)
128
- file_name = File.join(@db_dir, name + '.json')
129
- return ::Hash.new unless File.exist?(file_name)
130
-
131
- begin
132
- json = File.read(file_name)
133
- rescue => e
134
- PEROBS.log.fatal "Cannot read hash file '#{file_name}': #{e.message}"
135
- end
136
- JSON.parse(json, :create_additions => true)
137
- end
138
-
139
- # Store the given object into the cluster files.
140
- # @param obj [Hash] Object as defined by PEROBS::ObjectBase
141
- def put_object(obj, id)
142
- find_blob(id, true).write_object(id, serialize(obj))
143
- end
144
-
145
- # Load the given object from the filesystem.
146
- # @param id [Integer] object ID
147
- # @return [Hash] Object as defined by PEROBS::ObjectBase or nil if ID does
148
- # not exist
149
- def get_object(id)
150
- return nil unless (blob = find_blob(id)) && (obj = blob.read_object(id))
151
- deserialize(obj)
152
- end
153
-
154
- # This method must be called to initiate the marking process.
155
- def clear_marks
156
- each_blob { |blob| blob.clear_marks }
157
- end
158
-
159
- # Permanently delete all objects that have not been marked. Those are
160
- # orphaned and are no longer referenced by any actively used object.
161
- # @return [Array] List of IDs that have been removed from the DB.
162
- def delete_unmarked_objects
163
- deleted_ids = []
164
- each_blob { |blob| deleted_ids += blob.delete_unmarked_entries }
165
- deleted_ids
166
- end
167
-
168
- # Mark an object.
169
- # @param id [Integer] ID of the object to mark
170
- def mark(id)
171
- (blob = find_blob(id)) && blob.mark(id)
172
- end
173
-
174
- # Check if the object is marked.
175
- # @param id [Integer] ID of the object to check
176
- # @param ignore_errors [Boolean] If set to true no errors will be raised
177
- # for non-existing objects.
178
- def is_marked?(id, ignore_errors = false)
179
- (blob = find_blob(id)) && blob.is_marked?(id, ignore_errors)
180
- end
181
-
182
- # Basic consistency check.
183
- # @param repair [TrueClass/FalseClass] True if found errors should be
184
- # repaired.
185
- def check_db(repair = false)
186
- each_blob { |blob| blob.check(repair) }
187
- end
188
-
189
- # Check if the stored object is syntactically correct.
190
- # @param id [Integer] Object ID
191
- # @param repair [TrueClass/FalseClass] True if an repair attempt should be
192
- # made.
193
- # @return [TrueClass/FalseClass] True if the object is OK, otherwise
194
- # false.
195
- def check(id, repair)
196
- begin
197
- get_object(id)
198
- rescue => e
199
- PEROBS.log.error "Cannot read object with ID #{id}: #{e.message}"
200
- return false
201
- end
202
-
203
- true
204
- end
205
-
206
- # Store the given serialized object into the cluster files. This method is
207
- # for internal use only!
208
- # @param raw [String] Serialized Object as defined by PEROBS::ObjectBase
209
- # @param id [Integer] Object ID
210
- def put_raw_object(raw, id)
211
- find_blob(id, true).write_object(id, raw)
212
- end
213
-
214
- private
215
-
216
- def find_blob(id, create_missing_blob = false, dir_name = @db_dir)
217
- dir_bits = id & @dir_mask
218
- sub_dir_name = File.join(dir_name, @dir_format_string % dir_bits)
219
-
220
- if Dir.exist?(sub_dir_name)
221
- if File.exist?(File.join(sub_dir_name, 'index'))
222
- # The directory is a blob directory and not a BTree node dir.
223
- return BTreeBlob.new(sub_dir_name, self)
224
- end
225
- else
226
- Dir.glob(File.join(dir_name, '*.index')).each do |fqfn|
227
- # Extract the 01-part of the filename
228
- lsb_string = File.basename(fqfn)[0..-6]
229
- # Convert the lsb_string into a Integer
230
- lsb = Integer('0b' + lsb_string)
231
- # Bit mask to match the LSBs
232
- mask = (2 ** lsb_string.length) - 1
233
- if (id & mask) == lsb
234
- return TreeBlob.new(sub_dir_name, lsb_string, self)
235
- end
236
- end
237
- if create_missing_blob
238
- # Create the new blob directory.
239
- Dir.mkdir(dir_name)
240
- # And initialize the blob DB.
241
- return BTreeBlob.new(dir_name, self)
242
- else
243
- return nil
244
- end
245
- end
246
-
247
- # Discard the least significant @dir_bits bits and start over again
248
- # with the directory that matches the @dir_bits LSBs of the new ID.
249
- id = id >> @dir_bits
250
- end
251
-
252
- def each_blob(&block)
253
- each_blob_r(@db_dir, &block)
254
- end
255
-
256
- def each_blob_r(dir, &block)
257
- Dir.glob(File.join(dir, '*')) do |dir_name|
258
- if is_blob_dir?(dir_name)
259
- block.call(BTreeBlob.new(dir_name, self))
260
- else
261
- each_blob_r(dir_name, &block)
262
- end
263
- end
264
- end
265
-
266
- def is_blob_dir?(dir_name)
267
- # A blob directory contains an 'index' and 'data' file. This is in
268
- # contrast to BTree node directories that only contain other
269
- # directories.
270
- index_file = File.join(dir_name, 'index')
271
- File.exist?(index_file)
272
- end
273
-
274
- end
275
-
276
- end
277
-