perobs 0.0.1 → 1.0.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.
- 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
|