perobs 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +7 -9
- data/README.md +0 -4
- data/lib/perobs/Array.rb +6 -0
- data/lib/perobs/BTreeBlob.rb +327 -0
- data/lib/perobs/BTreeDB.rb +252 -0
- data/lib/perobs/ClassMap.rb +125 -0
- data/lib/perobs/DataBase.rb +21 -2
- data/lib/perobs/Hash.rb +8 -0
- data/lib/perobs/Object.rb +11 -0
- data/lib/perobs/ObjectBase.rb +12 -2
- data/lib/perobs/Store.rb +21 -7
- data/lib/perobs/version.rb +1 -1
- data/spec/{FileSystemDB_spec.rb → BTreeDB_spec.rb} +53 -9
- data/spec/ClassMap_spec.rb +70 -0
- data/spec/Store_spec.rb +43 -2
- metadata +9 -7
- data/lib/perobs/BlockDB.rb +0 -242
- data/lib/perobs/FileSystemDB.rb +0 -171
- data/lib/perobs/HashedBlocksDB.rb +0 -153
@@ -0,0 +1,125 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# = ClassMap.rb -- Persistent Ruby Object Store
|
4
|
+
#
|
5
|
+
# Copyright (c) 2015 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/DataBase'
|
29
|
+
|
30
|
+
module PEROBS
|
31
|
+
|
32
|
+
# PEROBS will usually store objects with a relatively small number of
|
33
|
+
# classes. Rather than storing the class name with each object, we map the
|
34
|
+
# class name to a numerical ID that represents the class in the store. This
|
35
|
+
# class handles the mapping and can convert class names into IDs and vice
|
36
|
+
# versa.
|
37
|
+
class ClassMap
|
38
|
+
|
39
|
+
# Create a ClassMap object for a given data base.
|
40
|
+
# @param db [DataBase]
|
41
|
+
def initialize(db)
|
42
|
+
@db = db
|
43
|
+
@by_class = {}
|
44
|
+
@by_id = []
|
45
|
+
read_map
|
46
|
+
end
|
47
|
+
|
48
|
+
# Get the ID for a given class.
|
49
|
+
# @param klass [String] Class
|
50
|
+
# @return [Fixnum] ID. If klass is not yet known a new ID will be
|
51
|
+
# allocated.
|
52
|
+
def class_to_id(klass)
|
53
|
+
@by_class[klass] || new_id(klass)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get the klass for a given ID.
|
57
|
+
# @param id [Fixnum]
|
58
|
+
# @return [String] String version of the class
|
59
|
+
def id_to_class(id)
|
60
|
+
@by_id[id]
|
61
|
+
end
|
62
|
+
|
63
|
+
# Rename a set of classes to new names.
|
64
|
+
# @param rename_map [Hash] Hash that maps old names to new names
|
65
|
+
def rename(rename_map)
|
66
|
+
@by_id.each.with_index do |klass, id|
|
67
|
+
# Some entries can be nil. Ignore them.
|
68
|
+
next unless klass
|
69
|
+
|
70
|
+
if (new_name = rename_map[klass])
|
71
|
+
# We have a rename request. Update the current @by_id entry.
|
72
|
+
@by_id[id] = new_name
|
73
|
+
# Remove the old class name from @by_class hash.
|
74
|
+
@by_class.delete(klass)
|
75
|
+
# Insert the new one with the current ID.
|
76
|
+
@by_class[new_name] = id
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Delete all classes unless they are contained in _classes_.
|
82
|
+
# @param classes [Array of String] List of the class names
|
83
|
+
def keep(classes)
|
84
|
+
@by_id.each.with_index do |klass, id|
|
85
|
+
unless classes.include?(klass)
|
86
|
+
# Delete the class from the @by_id list by setting the entry to nil.
|
87
|
+
@by_id[id] = nil
|
88
|
+
# Delete the corresponding @by_class entry as well.
|
89
|
+
@by_class.delete(klass)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def new_id(klass)
|
97
|
+
# Find the first 'nil' entry and return the index.
|
98
|
+
idx = @by_id.find_index(nil) || @by_id.length
|
99
|
+
|
100
|
+
# Insert the new class/ID touple into the hash and reverse map.
|
101
|
+
@by_class[klass] = idx
|
102
|
+
@by_id[idx] = klass
|
103
|
+
# Write the updated version into the data base.
|
104
|
+
write_map
|
105
|
+
|
106
|
+
# Return the new ID.
|
107
|
+
idx
|
108
|
+
end
|
109
|
+
|
110
|
+
def read_map
|
111
|
+
# Get the hash from the data base
|
112
|
+
@by_class = @db.get_hash('class_map')
|
113
|
+
# Build the reverse map from the hash.
|
114
|
+
@by_class.each do |klass, id|
|
115
|
+
@by_id[id] = klass
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def write_map
|
120
|
+
@db.put_hash('class_map', @by_class)
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
data/lib/perobs/DataBase.rb
CHANGED
@@ -41,6 +41,7 @@ module PEROBS
|
|
41
41
|
|
42
42
|
def initialize(serializer = :json)
|
43
43
|
@serializer = serializer
|
44
|
+
@config = {}
|
44
45
|
end
|
45
46
|
|
46
47
|
# Serialize the given object using the object serializer.
|
@@ -83,8 +84,7 @@ module PEROBS
|
|
83
84
|
end
|
84
85
|
|
85
86
|
# Generate a new unique ID. It uses random numbers between 0 and 2**64 -
|
86
|
-
# 1.
|
87
|
-
# include? method.
|
87
|
+
# 1.
|
88
88
|
# @return [Fixnum or Bignum]
|
89
89
|
def new_id
|
90
90
|
begin
|
@@ -97,6 +97,25 @@ module PEROBS
|
|
97
97
|
id
|
98
98
|
end
|
99
99
|
|
100
|
+
# Check a config option and adjust it if needed.
|
101
|
+
# @param name [String] Name of the config option.
|
102
|
+
def check_option(name)
|
103
|
+
value = instance_variable_get('@' + name)
|
104
|
+
|
105
|
+
if @config.include?(name)
|
106
|
+
# The database already existed and has a setting for this config
|
107
|
+
# option. If it does not match the instance variable, adjust the
|
108
|
+
# instance variable accordingly.
|
109
|
+
unless @config[name] == value
|
110
|
+
instance_variable_set('@' + name, @config[name])
|
111
|
+
end
|
112
|
+
else
|
113
|
+
# There is no such config option yet. Create it with the value of the
|
114
|
+
# corresponding instance variable.
|
115
|
+
@config[name] = value
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
100
119
|
private
|
101
120
|
|
102
121
|
# Ensure that we have a directory to store the DB items.
|
data/lib/perobs/Hash.rb
CHANGED
@@ -163,6 +163,14 @@ module PEROBS
|
|
163
163
|
@data = data
|
164
164
|
end
|
165
165
|
|
166
|
+
# Textual dump for debugging purposes
|
167
|
+
# @return [String]
|
168
|
+
def inspect
|
169
|
+
"{\n" +
|
170
|
+
@data.map { |k, v| " #{k.inspect}=>#{v.inspect}" }.join(",\n") +
|
171
|
+
"\n}\n"
|
172
|
+
end
|
173
|
+
|
166
174
|
private
|
167
175
|
|
168
176
|
def _serialize
|
data/lib/perobs/Object.rb
CHANGED
@@ -133,6 +133,17 @@ module PEROBS
|
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
136
|
+
# Textual dump for debugging purposes
|
137
|
+
# @return [String]
|
138
|
+
def inspect
|
139
|
+
"{\n" +
|
140
|
+
self.class.attributes.map do |attr|
|
141
|
+
ivar = ('@' + attr.to_s).to_sym
|
142
|
+
" #{attr.inspect}=>#{instance_variable_get(ivar).inspect}"
|
143
|
+
end.join(",\n") +
|
144
|
+
"\n}\n"
|
145
|
+
end
|
146
|
+
|
136
147
|
private
|
137
148
|
|
138
149
|
# Return a single data structure that holds all persistent data for this
|
data/lib/perobs/ObjectBase.rb
CHANGED
@@ -25,6 +25,8 @@
|
|
25
25
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
26
26
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27
27
|
|
28
|
+
require 'perobs/ClassMap'
|
29
|
+
|
28
30
|
module PEROBS
|
29
31
|
|
30
32
|
# This class is used to replace a direct reference to another Ruby object by
|
@@ -32,6 +34,13 @@ module PEROBS
|
|
32
34
|
# since it's no longer referenced once it has been evicted from the
|
33
35
|
# PEROBS::Store cache.
|
34
36
|
class POReference < Struct.new(:id)
|
37
|
+
|
38
|
+
# Textual dump for debugging purposes
|
39
|
+
# @return [String]
|
40
|
+
def inspect
|
41
|
+
"@#{id}"
|
42
|
+
end
|
43
|
+
|
35
44
|
end
|
36
45
|
|
37
46
|
# Base class for all persistent objects. It provides the functionality
|
@@ -62,7 +71,7 @@ module PEROBS
|
|
62
71
|
@_stash_map = nil
|
63
72
|
|
64
73
|
db_obj = {
|
65
|
-
'
|
74
|
+
'class_id' => @store.class_map.class_to_id(self.class.to_s),
|
66
75
|
'data' => _serialize
|
67
76
|
}
|
68
77
|
@store.db.put_object(db_obj, @_id)
|
@@ -74,8 +83,9 @@ module PEROBS
|
|
74
83
|
# Read the object from database.
|
75
84
|
db_obj = store.db.get_object(id)
|
76
85
|
|
86
|
+
klass = store.class_map.id_to_class(db_obj['class_id'])
|
77
87
|
# Call the constructor of the specified class.
|
78
|
-
obj = Object.const_get(
|
88
|
+
obj = Object.const_get(klass).new(store)
|
79
89
|
# The object gets created with a new ID by default. We need to restore
|
80
90
|
# the old one.
|
81
91
|
obj._change_id(id)
|
data/lib/perobs/Store.rb
CHANGED
@@ -26,8 +26,8 @@
|
|
26
26
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27
27
|
|
28
28
|
require 'perobs/Cache'
|
29
|
-
require 'perobs/
|
30
|
-
require 'perobs/
|
29
|
+
require 'perobs/ClassMap'
|
30
|
+
require 'perobs/BTreeDB'
|
31
31
|
require 'perobs/Object'
|
32
32
|
require 'perobs/Hash'
|
33
33
|
require 'perobs/Array'
|
@@ -49,16 +49,16 @@ module PEROBS
|
|
49
49
|
# objects are all going to persistent objects again.
|
50
50
|
class Store
|
51
51
|
|
52
|
-
attr_reader :db, :cache
|
52
|
+
attr_reader :db, :cache, :class_map
|
53
53
|
|
54
54
|
# Create a new Store.
|
55
55
|
# @param data_base [String] the name of the database
|
56
56
|
# @param options [Hash] various options to affect the operation of the
|
57
57
|
# database. Currently the following options are supported:
|
58
58
|
# :engine : The class that provides the back-end storage
|
59
|
-
# engine. By default
|
59
|
+
# engine. By default BTreeDB is used. A user
|
60
60
|
# can provide it's own storage engine that must
|
61
|
-
# conform to the same API exposed by
|
61
|
+
# conform to the same API exposed by BTreeBlobsDB.
|
62
62
|
# :cache_bits : the number of bits used for cache indexing. The
|
63
63
|
# cache will hold 2 to the power of bits number of
|
64
64
|
# objects. We have separate caches for reading and
|
@@ -81,7 +81,10 @@ module PEROBS
|
|
81
81
|
# Unfortunately, it is 10x slower than marshal.
|
82
82
|
def initialize(data_base, options = {})
|
83
83
|
# Create a backing store handler
|
84
|
-
@db = (options[:engine] ||
|
84
|
+
@db = (options[:engine] || BTreeDB).new(data_base, options)
|
85
|
+
# Create a map that can translate classes to numerical IDs and vice
|
86
|
+
# versa.
|
87
|
+
@class_map = ClassMap.new(@db)
|
85
88
|
|
86
89
|
# The Cache reduces read and write latencies by keeping a subset of the
|
87
90
|
# objects in memory.
|
@@ -192,6 +195,9 @@ module PEROBS
|
|
192
195
|
# @param repair [TrueClass/FalseClass] true if a repair attempt should be
|
193
196
|
# made.
|
194
197
|
def check(repair = true)
|
198
|
+
# Run basic consistency checks first.
|
199
|
+
@db.check_db(repair)
|
200
|
+
|
195
201
|
@db.clear_marks
|
196
202
|
# A buffer to hold a working set of object IDs.
|
197
203
|
stack = []
|
@@ -269,12 +275,20 @@ module PEROBS
|
|
269
275
|
end
|
270
276
|
end
|
271
277
|
|
278
|
+
# Rename classes of objects stored in the data base.
|
279
|
+
# @param rename_map [Hash] Hash that maps the old name to the new name
|
280
|
+
def rename_classes(rename_map)
|
281
|
+
@class_map.rename(rename_map)
|
282
|
+
end
|
283
|
+
|
272
284
|
private
|
273
285
|
|
274
286
|
# Mark phase of a mark-and-sweep garbage collector. It will mark all
|
275
287
|
# objects that are reachable from the root objects.
|
276
288
|
def mark
|
277
|
-
|
289
|
+
classes = Set.new
|
290
|
+
each { |obj| classes.add(obj.class) }
|
291
|
+
@class_map.keep(classes.map { |c| c.to_s })
|
278
292
|
end
|
279
293
|
|
280
294
|
# Sweep phase of a mark-and-sweep garbage collector. It will remove all
|
data/lib/perobs/version.rb
CHANGED
@@ -28,12 +28,12 @@ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
|
28
28
|
require 'fileutils'
|
29
29
|
require 'time'
|
30
30
|
|
31
|
-
require 'perobs/
|
31
|
+
require 'perobs/BTreeDB'
|
32
32
|
|
33
|
-
|
34
|
-
end
|
33
|
+
describe PEROBS::BTreeDB do
|
35
34
|
|
36
|
-
|
35
|
+
class UStruct < Struct.new(:first, :second, :third)
|
36
|
+
end
|
37
37
|
|
38
38
|
before(:all) do
|
39
39
|
FileUtils.rm_rf('fs_test')
|
@@ -44,12 +44,20 @@ describe PEROBS::FileSystemDB do
|
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'should create database' do
|
47
|
-
@db = PEROBS::
|
47
|
+
@db = PEROBS::BTreeDB.new('fs_test')
|
48
48
|
Dir.exists?('fs_test').should be_true
|
49
49
|
end
|
50
50
|
|
51
|
+
it 'should write and read a simple Hash' do
|
52
|
+
@db = PEROBS::BTreeDB.new('fs_test')
|
53
|
+
@db.get_hash('test').should == {}
|
54
|
+
h = { 'A' => 1, 'B' => 2, 'D' => 4 }
|
55
|
+
@db.put_hash('test', h)
|
56
|
+
@db.get_hash('test').should == h
|
57
|
+
end
|
58
|
+
|
51
59
|
it 'should support object insertion and retrieval' do
|
52
|
-
@db = PEROBS::
|
60
|
+
@db = PEROBS::BTreeDB.new('fs_test')
|
53
61
|
@db.include?(0).should be_false
|
54
62
|
h = {
|
55
63
|
'String' => 'What god has wrought',
|
@@ -68,7 +76,7 @@ describe PEROBS::FileSystemDB do
|
|
68
76
|
|
69
77
|
it 'should support most Ruby objects types' do
|
70
78
|
[ :marshal, :yaml ].each do |serializer|
|
71
|
-
@db = PEROBS::
|
79
|
+
@db = PEROBS::BTreeDB.new('fs_test', { :serializer => serializer })
|
72
80
|
@db.include?(0).should be_false
|
73
81
|
h = {
|
74
82
|
'String' => 'What god has wrought',
|
@@ -79,17 +87,53 @@ describe PEROBS::FileSystemDB do
|
|
79
87
|
'nil' => nil,
|
80
88
|
'Array' => [ 0, 1, 2, 3 ],
|
81
89
|
'Time' => Time.parse('2015-05-14-13:52:17'),
|
82
|
-
'Struct' =>
|
90
|
+
'Struct' => UStruct.new("Where's", 'your', 'towel?')
|
83
91
|
}
|
84
92
|
@db.put_object(h, 0)
|
85
93
|
@db.include?(0).should be_true
|
86
94
|
@db.check(0, false).should be_true
|
87
95
|
@db.get_object(0).should == h
|
96
|
+
FileUtils.rm_rf('fs_test')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should put and get multiple objects in same dir' do
|
101
|
+
@db = PEROBS::BTreeDB.new('fs_test')
|
102
|
+
0.upto(10) do |i|
|
103
|
+
@db.put_object({ "foo #{i}" => i }, i)
|
88
104
|
end
|
105
|
+
0.upto(10) do |i|
|
106
|
+
@db.get_object(i)["foo #{i}"].should == i
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should handle deleted objects propery' do
|
111
|
+
@db = PEROBS::BTreeDB.new('fs_test')
|
112
|
+
@db.put_object({ 'a' => 'a' * 257 }, 0)
|
113
|
+
@db.put_object({ 'b' => 'b' * 513 }, 1)
|
114
|
+
@db.put_object({ 'c' => 'c' * 129 }, 2)
|
115
|
+
@db.put_object({ 'd' => 'd' * 1025 }, 3)
|
116
|
+
# Delete some objects
|
117
|
+
@db.clear_marks
|
118
|
+
@db.mark(0)
|
119
|
+
@db.mark(2)
|
120
|
+
@db.delete_unmarked_objects
|
121
|
+
|
122
|
+
@db.put_object({ 'A' => 'a' * 257 }, 4)
|
123
|
+
@db.put_object({ 'B' => 'b' * 513 }, 5)
|
124
|
+
@db.put_object({ 'C' => 'c' * 129 }, 6)
|
125
|
+
@db.put_object({ 'D' => 'd' * 1025 }, 7)
|
126
|
+
|
127
|
+
@db.get_object(0).should == { 'a' => 'a' * 257 }
|
128
|
+
@db.get_object(2).should == { 'c' => 'c' * 129 }
|
129
|
+
@db.get_object(4).should == { 'A' => 'a' * 257 }
|
130
|
+
@db.get_object(5).should == { 'B' => 'b' * 513 }
|
131
|
+
@db.get_object(6).should == { 'C' => 'c' * 129 }
|
132
|
+
@db.get_object(7).should == { 'D' => 'd' * 1025 }
|
89
133
|
end
|
90
134
|
|
91
135
|
it 'should mark objects and detect markings' do
|
92
|
-
@db = PEROBS::
|
136
|
+
@db = PEROBS::BTreeDB.new('fs_test')
|
93
137
|
h = { 'a' => 'z' }
|
94
138
|
@db.put_object(h, 1)
|
95
139
|
@db.put_object(h, 2)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Copyright (c) 2015 by Chris Schlaeger <chris@taskjuggler.org>
|
4
|
+
#
|
5
|
+
# MIT License
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
# a copy of this software and associated documentation files (the
|
9
|
+
# "Software"), to deal in the Software without restriction, including
|
10
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
13
|
+
# the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be
|
16
|
+
# included in all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
|
+
|
26
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
27
|
+
|
28
|
+
require 'perobs/ClassMap'
|
29
|
+
require 'perobs/BTreeDB'
|
30
|
+
|
31
|
+
describe PEROBS::ClassMap do
|
32
|
+
|
33
|
+
before(:all) do
|
34
|
+
FileUtils.rm_rf('fs_test')
|
35
|
+
@db = PEROBS::BTreeDB.new('fs_test')
|
36
|
+
@map = PEROBS::ClassMap.new(@db)
|
37
|
+
end
|
38
|
+
|
39
|
+
after(:all) do
|
40
|
+
FileUtils.rm_rf('fs_test')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should return nil for an unknown ID' do
|
44
|
+
@map.id_to_class(0).should be_nil
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should add a class' do
|
48
|
+
@map.class_to_id('Foo').should == 0
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should find the class again' do
|
52
|
+
@map.id_to_class(0).should == 'Foo'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should still return nil for an unknown ID' do
|
56
|
+
@map.id_to_class(1).should be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should forget classes not in keep list' do
|
60
|
+
@map.class_to_id('Bar').should == 1
|
61
|
+
@map.class_to_id('Foobar').should == 2
|
62
|
+
@map.keep([ 'Bar' ])
|
63
|
+
@map.id_to_class(0).should be_nil
|
64
|
+
@map.id_to_class(1).should == 'Bar'
|
65
|
+
@map.id_to_class(2).should be_nil
|
66
|
+
@map.class_to_id('Foo1').should == 0
|
67
|
+
@map.class_to_id('Foo2').should == 2
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/spec/Store_spec.rb
CHANGED
@@ -45,6 +45,19 @@ class Person < PEROBS::Object
|
|
45
45
|
|
46
46
|
end
|
47
47
|
|
48
|
+
class PersonN < PEROBS::Object
|
49
|
+
|
50
|
+
po_attr :name, :zip, :bmi, :married, :related, :relatives
|
51
|
+
|
52
|
+
def initialize(store)
|
53
|
+
super
|
54
|
+
init_attr(:name, '')
|
55
|
+
init_attr(:bmi, 22.2)
|
56
|
+
init_attr(:married, false)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
48
61
|
describe PEROBS::Store do
|
49
62
|
|
50
63
|
before(:all) do
|
@@ -96,7 +109,7 @@ describe PEROBS::Store do
|
|
96
109
|
|
97
110
|
@store.sync
|
98
111
|
|
99
|
-
@store = PEROBS::Store.new('test_db'
|
112
|
+
@store = PEROBS::Store.new('test_db')
|
100
113
|
john = @store['john']
|
101
114
|
john.name.should == 'John'
|
102
115
|
john.zip.should == 4060
|
@@ -127,6 +140,34 @@ describe PEROBS::Store do
|
|
127
140
|
end
|
128
141
|
end
|
129
142
|
|
143
|
+
it 'should support renaming of classes' do
|
144
|
+
@store = PEROBS::Store.new('test_db')
|
145
|
+
@store['john'] = john = Person.new(@store)
|
146
|
+
john.name = 'John'
|
147
|
+
john.zip = 4060
|
148
|
+
john.bmi = 25.5
|
149
|
+
@store['jane'] = jane = Person.new(@store)
|
150
|
+
jane.name = 'Jane'
|
151
|
+
jane.related = john
|
152
|
+
jane.married = true
|
153
|
+
jane.relatives = 'test'
|
154
|
+
|
155
|
+
@store.sync
|
156
|
+
|
157
|
+
@store = PEROBS::Store.new('test_db')
|
158
|
+
@store.rename_classes({ 'Person' => 'PersonN' })
|
159
|
+
john = @store['john']
|
160
|
+
john.name.should == 'John'
|
161
|
+
john.zip.should == 4060
|
162
|
+
john.bmi.should == 25.5
|
163
|
+
john.married.should be_false
|
164
|
+
john.related.should be_nil
|
165
|
+
jane = @store['jane']
|
166
|
+
jane.name.should == 'Jane'
|
167
|
+
jane.related.should == john
|
168
|
+
jane.married.should be_true
|
169
|
+
end
|
170
|
+
|
130
171
|
it 'should detect modification to non-working objects' do
|
131
172
|
@store = PEROBS::Store.new('test_db', :cache_bits => 3)
|
132
173
|
0.upto(20) do |i|
|
@@ -346,7 +387,7 @@ describe PEROBS::Store do
|
|
346
387
|
end
|
347
388
|
|
348
389
|
it 'should survive a real world usage test' do
|
349
|
-
options = { :engine => PEROBS::
|
390
|
+
options = { :engine => PEROBS::BTreeDB, :dir_bits => 4 }
|
350
391
|
@store = PEROBS::Store.new('test_db', options)
|
351
392
|
ref = {}
|
352
393
|
|
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: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Schlaeger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,19 +66,20 @@ files:
|
|
66
66
|
- Rakefile
|
67
67
|
- lib/perobs.rb
|
68
68
|
- lib/perobs/Array.rb
|
69
|
-
- lib/perobs/
|
69
|
+
- lib/perobs/BTreeBlob.rb
|
70
|
+
- lib/perobs/BTreeDB.rb
|
70
71
|
- lib/perobs/Cache.rb
|
72
|
+
- lib/perobs/ClassMap.rb
|
71
73
|
- lib/perobs/DataBase.rb
|
72
|
-
- lib/perobs/FileSystemDB.rb
|
73
74
|
- lib/perobs/Hash.rb
|
74
|
-
- lib/perobs/HashedBlocksDB.rb
|
75
75
|
- lib/perobs/Object.rb
|
76
76
|
- lib/perobs/ObjectBase.rb
|
77
77
|
- lib/perobs/Store.rb
|
78
78
|
- lib/perobs/version.rb
|
79
79
|
- perobs.gemspec
|
80
80
|
- spec/Array_spec.rb
|
81
|
-
- spec/
|
81
|
+
- spec/BTreeDB_spec.rb
|
82
|
+
- spec/ClassMap_spec.rb
|
82
83
|
- spec/Hash_spec.rb
|
83
84
|
- spec/Object_spec.rb
|
84
85
|
- spec/Store_spec.rb
|
@@ -113,7 +114,8 @@ specification_version: 4
|
|
113
114
|
summary: Persistent Ruby Object Store
|
114
115
|
test_files:
|
115
116
|
- spec/Array_spec.rb
|
116
|
-
- spec/
|
117
|
+
- spec/BTreeDB_spec.rb
|
118
|
+
- spec/ClassMap_spec.rb
|
117
119
|
- spec/Hash_spec.rb
|
118
120
|
- spec/Object_spec.rb
|
119
121
|
- spec/Store_spec.rb
|