perobs 4.0.0 → 4.1.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/lib/perobs.rb +1 -0
- data/lib/perobs/Array.rb +66 -19
- data/lib/perobs/BTree.rb +83 -12
- data/lib/perobs/BTreeBlob.rb +1 -1
- data/lib/perobs/BTreeDB.rb +2 -2
- data/lib/perobs/BTreeNode.rb +365 -85
- data/lib/perobs/BigArray.rb +267 -0
- data/lib/perobs/BigArrayNode.rb +998 -0
- data/lib/perobs/BigHash.rb +262 -0
- data/lib/perobs/BigTree.rb +184 -0
- data/lib/perobs/BigTreeNode.rb +873 -0
- data/lib/perobs/ConsoleProgressMeter.rb +61 -0
- data/lib/perobs/DataBase.rb +4 -3
- data/lib/perobs/DynamoDB.rb +57 -15
- data/lib/perobs/EquiBlobsFile.rb +143 -51
- data/lib/perobs/FNV_Hash_1a_64.rb +54 -0
- data/lib/perobs/FlatFile.rb +363 -203
- data/lib/perobs/FlatFileBlobHeader.rb +98 -54
- data/lib/perobs/FlatFileDB.rb +42 -20
- data/lib/perobs/Hash.rb +58 -13
- data/lib/perobs/IDList.rb +144 -0
- data/lib/perobs/IDListPage.rb +107 -0
- data/lib/perobs/IDListPageFile.rb +180 -0
- data/lib/perobs/IDListPageRecord.rb +142 -0
- data/lib/perobs/Object.rb +18 -15
- data/lib/perobs/ObjectBase.rb +38 -4
- data/lib/perobs/PersistentObjectCache.rb +53 -67
- data/lib/perobs/PersistentObjectCacheLine.rb +24 -12
- data/lib/perobs/ProgressMeter.rb +97 -0
- data/lib/perobs/SpaceTree.rb +21 -12
- data/lib/perobs/SpaceTreeNode.rb +53 -61
- data/lib/perobs/Store.rb +71 -32
- data/lib/perobs/version.rb +1 -1
- data/perobs.gemspec +4 -4
- data/test/Array_spec.rb +15 -6
- data/test/BTree_spec.rb +5 -2
- data/test/BigArray_spec.rb +214 -0
- data/test/BigHash_spec.rb +144 -0
- data/test/BigTreeNode_spec.rb +153 -0
- data/test/BigTree_spec.rb +259 -0
- data/test/EquiBlobsFile_spec.rb +105 -1
- data/test/FNV_Hash_1a_64_spec.rb +59 -0
- data/test/FlatFileDB_spec.rb +63 -14
- data/test/Hash_spec.rb +1 -2
- data/test/IDList_spec.rb +77 -0
- data/test/LegacyDBs/LegacyDB.rb +151 -0
- data/test/LegacyDBs/version_3/class_map.json +1 -0
- data/test/LegacyDBs/version_3/config.json +1 -0
- data/test/LegacyDBs/version_3/database.blobs +0 -0
- data/test/LegacyDBs/version_3/database_spaces.blobs +0 -0
- data/test/LegacyDBs/version_3/index.blobs +0 -0
- data/test/LegacyDBs/version_3/version +1 -0
- data/test/LockFile_spec.rb +9 -6
- data/test/SpaceTree_spec.rb +4 -1
- data/test/Store_spec.rb +290 -199
- data/test/spec_helper.rb +9 -4
- metadata +47 -10
- data/lib/perobs/TreeDB.rb +0 -277
@@ -48,12 +48,13 @@ module PEROBS
|
|
48
48
|
# The 'pack()' format of the header.
|
49
49
|
FORMAT = 'CQQL'
|
50
50
|
# The length of the header in bytes.
|
51
|
-
LENGTH =
|
51
|
+
LENGTH = 25
|
52
52
|
VALID_FLAG_BIT = 0
|
53
53
|
COMPRESSED_FLAG_BIT = 2
|
54
54
|
OUTDATED_FLAG_BIT = 3
|
55
55
|
|
56
56
|
attr_reader :addr, :flags, :length, :id, :crc
|
57
|
+
attr_accessor :corruption_start
|
57
58
|
|
58
59
|
# Create a new FlatFileBlobHeader with the given flags, length, id and crc.
|
59
60
|
# @param file [File] the FlatFile that contains the header
|
@@ -69,50 +70,105 @@ module PEROBS
|
|
69
70
|
@length = length
|
70
71
|
@id = id
|
71
72
|
@crc = crc
|
73
|
+
# This is only set if the header is preceded by a corrupted blob.
|
74
|
+
@corruption_start = nil
|
72
75
|
end
|
73
76
|
|
74
77
|
# Read the header from the given File.
|
75
78
|
# @param file [File]
|
76
|
-
# @
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
# @param addr [Integer] address in the file to start reading. If no
|
80
|
+
# address is specified use the current position in the file.
|
81
|
+
# @param id [Integer] Optional ID that the header should have. If no id is
|
82
|
+
# specified there is no check against the actual ID done.
|
83
|
+
# @return FlatFileBlobHeader or nil if there are no more blobs to read in
|
84
|
+
# the file.
|
85
|
+
def FlatFileBlobHeader::read(file, addr = nil, id = nil)
|
86
|
+
# If an address was specified we expect the read to always succeed. If
|
87
|
+
# no address is specified and we can't read the header we generate an
|
88
|
+
# error message but it is not fatal.
|
89
|
+
errors_are_fatal = !addr.nil?
|
90
|
+
|
91
|
+
mode = :searching_next_header
|
92
|
+
addr = file.pos unless addr
|
93
|
+
buf = nil
|
94
|
+
corruption_start = nil
|
95
|
+
|
96
|
+
loop do
|
97
|
+
buf_with_crc = nil
|
98
|
+
begin
|
99
|
+
file.seek(addr)
|
100
|
+
buf_with_crc = file.read(LENGTH)
|
101
|
+
rescue IOError => e
|
102
|
+
if errors_are_fatal
|
103
|
+
PEROBS.log.fatal "Cannot read blob header in flat file DB at " +
|
104
|
+
"address #{addr}: #{e.message}"
|
105
|
+
else
|
106
|
+
PEROBS.log.error "Cannot read blob header in flat file DB: " +
|
107
|
+
e.message
|
108
|
+
return nil
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Did we read anything?
|
113
|
+
if buf_with_crc.nil?
|
114
|
+
if errors_are_fatal
|
115
|
+
PEROBS.log.fatal "Cannot read blob header " +
|
116
|
+
"#{id ? "for ID #{id} " : ''}at address #{addr}"
|
117
|
+
else
|
118
|
+
# We have reached the end of the file.
|
119
|
+
return nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Did we get the full header?
|
124
|
+
if buf_with_crc.length != LENGTH
|
125
|
+
PEROBS.log.error "Incomplete FlatFileBlobHeader: Only " +
|
126
|
+
"#{buf_with_crc.length} " +
|
127
|
+
"bytes of #{LENGTH} could be read "
|
128
|
+
"#{id ? "for ID #{id} " : ''}at address #{addr}"
|
129
|
+
return nil
|
130
|
+
end
|
131
|
+
|
132
|
+
# Check the CRC of the header
|
133
|
+
buf = buf_with_crc[0..-5]
|
134
|
+
crc = buf_with_crc[-4..-1].unpack('L')[0]
|
135
|
+
|
136
|
+
if (read_crc = Zlib.crc32(buf, 0)) == crc
|
137
|
+
# We have found a valid header.
|
138
|
+
if corruption_start
|
139
|
+
PEROBS.log.error "FlatFile corruption ends at #{addr}. " +
|
140
|
+
"#{addr - corruption_start} bytes skipped. Some data may " +
|
141
|
+
"not be recoverable."
|
142
|
+
end
|
143
|
+
break
|
144
|
+
else
|
145
|
+
if errors_are_fatal
|
146
|
+
PEROBS.log.fatal "FlatFile Header CRC mismatch at address " +
|
147
|
+
"#{addr}. Header CRC is #{'%08x' % read_crc} but should be " +
|
148
|
+
"#{'%08x' % crc}."
|
149
|
+
else
|
150
|
+
if corruption_start.nil?
|
151
|
+
PEROBS.log.error "FlatFile corruption found. The FlatFile " +
|
152
|
+
"Header CRC mismatch at address #{addr}. Header CRC is " +
|
153
|
+
"#{'%08x' % read_crc} but should be #{'%08x' % crc}. Trying " +
|
154
|
+
"to find the next header."
|
155
|
+
corruption_start = addr
|
156
|
+
end
|
157
|
+
# The blob file is corrupted. There is no valid header at the
|
158
|
+
# current position in the file. We now try to find the next valid
|
159
|
+
# header by iterating over the remainder of the file advanding one
|
160
|
+
# byte with each step until we hit the end of the file or find the
|
161
|
+
# next valid header.
|
162
|
+
addr += 1
|
163
|
+
end
|
164
|
+
end
|
84
165
|
end
|
85
166
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
PEROBS.log.error "Incomplete FlatFileBlobHeader: Only #{buf.length} " +
|
90
|
-
"bytes of #{LENGTH} could be read"
|
91
|
-
return nil
|
167
|
+
header = FlatFileBlobHeader.new(file, addr, *buf.unpack(FORMAT))
|
168
|
+
if corruption_start
|
169
|
+
header.corruption_start = corruption_start
|
92
170
|
end
|
93
171
|
|
94
|
-
FlatFileBlobHeader.new(file, addr, *buf.unpack(FORMAT))
|
95
|
-
end
|
96
|
-
|
97
|
-
# Read the header from the given File.
|
98
|
-
# @param file [File]
|
99
|
-
# @param addr [Integer] address in the file to start reading
|
100
|
-
# @param id [Integer] Optional ID that the header should have
|
101
|
-
# @return FlatFileBlobHeader
|
102
|
-
def FlatFileBlobHeader::read_at(file, addr, id = nil)
|
103
|
-
buf = nil
|
104
|
-
begin
|
105
|
-
file.seek(addr)
|
106
|
-
buf = file.read(LENGTH)
|
107
|
-
rescue IOError => e
|
108
|
-
PEROBS.log.fatal "Cannot read blob in flat file DB: #{e.message}"
|
109
|
-
end
|
110
|
-
if buf.nil? || buf.length != LENGTH
|
111
|
-
PEROBS.log.fatal "Cannot read blob header " +
|
112
|
-
"#{id ? "for ID #{id} " : ''}at address " +
|
113
|
-
"#{addr}"
|
114
|
-
end
|
115
|
-
header = FlatFileBlobHeader.new(file, addr, *buf.unpack(FORMAT))
|
116
172
|
if id && header.id != id
|
117
173
|
PEROBS.log.fatal "Mismatch between FlatFile index and blob file " +
|
118
174
|
"found. FlatFile has entry with ID #{header.id} at address " +
|
@@ -123,11 +179,12 @@ module PEROBS
|
|
123
179
|
end
|
124
180
|
|
125
181
|
# Write the header to a given File.
|
126
|
-
# @param file [File]
|
127
182
|
def write
|
128
183
|
begin
|
184
|
+
buf = [ @flags, @length, @id, @crc].pack(FORMAT)
|
185
|
+
crc = Zlib.crc32(buf, 0)
|
129
186
|
@file.seek(@addr)
|
130
|
-
@file.write(
|
187
|
+
@file.write(buf + [ crc ].pack('L'))
|
131
188
|
rescue IOError => e
|
132
189
|
PEROBS.log.fatal "Cannot write blob header into flat file DB: " +
|
133
190
|
e.message
|
@@ -135,11 +192,9 @@ module PEROBS
|
|
135
192
|
end
|
136
193
|
|
137
194
|
# Reset all the flags bit to 0. This marks the blob as invalid.
|
138
|
-
# @param file [File] The file handle of the blob file.
|
139
|
-
# @param addr [Integer] The address of the header
|
140
195
|
def clear_flags
|
141
196
|
@flags = 0
|
142
|
-
|
197
|
+
write
|
143
198
|
end
|
144
199
|
|
145
200
|
# Return true if the header is for a non-empty blob.
|
@@ -156,7 +211,7 @@ module PEROBS
|
|
156
211
|
# transaction has been completed.
|
157
212
|
def set_outdated_flag
|
158
213
|
set_flag(OUTDATED_FLAG_BIT)
|
159
|
-
|
214
|
+
write
|
160
215
|
end
|
161
216
|
|
162
217
|
# Return true if the blob contains outdated data.
|
@@ -166,17 +221,6 @@ module PEROBS
|
|
166
221
|
|
167
222
|
private
|
168
223
|
|
169
|
-
def write_flags
|
170
|
-
begin
|
171
|
-
@file.seek(@addr)
|
172
|
-
@file.write([ @flags ].pack('C'))
|
173
|
-
@file.flush
|
174
|
-
rescue IOError => e
|
175
|
-
PEROBS.log.fatal "Writing flags of FlatFileBlobHeader with ID #{@id} " +
|
176
|
-
"failed: #{e.message}"
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
224
|
def bit_set?(n)
|
181
225
|
mask = 1 << n
|
182
226
|
@flags & mask == mask
|
data/lib/perobs/FlatFileDB.rb
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
#
|
3
3
|
# = FlatFileDB.rb -- Persistent Ruby Object Store
|
4
4
|
#
|
5
|
-
# Copyright (c) 2015, 2016
|
5
|
+
# Copyright (c) 2015, 2016, 2017, 2018
|
6
|
+
# by Chris Schlaeger <chris@taskjuggler.org>
|
6
7
|
#
|
7
8
|
# MIT License
|
8
9
|
#
|
@@ -41,7 +42,7 @@ module PEROBS
|
|
41
42
|
|
42
43
|
# This version number increases whenever the on-disk format changes in a
|
43
44
|
# way that requires conversion actions after an update.
|
44
|
-
VERSION =
|
45
|
+
VERSION = 4
|
45
46
|
|
46
47
|
attr_reader :max_blob_size
|
47
48
|
|
@@ -50,13 +51,17 @@ module PEROBS
|
|
50
51
|
# @param options [Hash] options to customize the behavior. Currently only
|
51
52
|
# the following options are supported:
|
52
53
|
# :serializer : Can be :marshal, :json, :yaml
|
54
|
+
# :progressmeter : Reference to a ProgressMeter object
|
55
|
+
# :log : IO that should be used for logging
|
56
|
+
# :log_level : Minimum Logger level to log
|
53
57
|
def initialize(db_name, options = {})
|
54
|
-
super(options
|
58
|
+
super(options)
|
55
59
|
|
56
60
|
@db_dir = db_name
|
57
61
|
# Create the database directory if it doesn't exist yet.
|
58
62
|
ensure_dir_exists(@db_dir)
|
59
|
-
PEROBS.log.
|
63
|
+
PEROBS.log.level = options[:log_level] if options[:log_level]
|
64
|
+
PEROBS.log.open(options[:log] || File.join(@db_dir, 'log'))
|
60
65
|
check_version_and_upgrade
|
61
66
|
|
62
67
|
# Read the existing DB config.
|
@@ -68,7 +73,7 @@ module PEROBS
|
|
68
73
|
|
69
74
|
# Open the FlatFileDB for transactions.
|
70
75
|
def open
|
71
|
-
@flat_file = FlatFile.new(@db_dir)
|
76
|
+
@flat_file = FlatFile.new(@db_dir, @progressmeter)
|
72
77
|
@flat_file.open
|
73
78
|
PEROBS.log.info "FlatFile '#{@db_dir}' opened"
|
74
79
|
end
|
@@ -143,8 +148,9 @@ module PEROBS
|
|
143
148
|
end
|
144
149
|
end
|
145
150
|
|
146
|
-
|
147
|
-
|
151
|
+
# @return [Integer] Number of objects stored in the DB.
|
152
|
+
def item_counter
|
153
|
+
@flat_file.item_counter
|
148
154
|
end
|
149
155
|
|
150
156
|
# This method must be called to initiate the marking process.
|
@@ -154,7 +160,7 @@ module PEROBS
|
|
154
160
|
|
155
161
|
# Permanently delete all objects that have not been marked. Those are
|
156
162
|
# orphaned and are no longer referenced by any actively used object.
|
157
|
-
# @return [
|
163
|
+
# @return [Integer] Number of the removed objects from the DB.
|
158
164
|
def delete_unmarked_objects
|
159
165
|
@flat_file.delete_unmarked_objects
|
160
166
|
end
|
@@ -226,7 +232,8 @@ module PEROBS
|
|
226
232
|
"'#{version_file}': " + e.message
|
227
233
|
end
|
228
234
|
else
|
229
|
-
#
|
235
|
+
# The DB is brand new.
|
236
|
+
version = VERSION
|
230
237
|
write_version_file(version_file)
|
231
238
|
end
|
232
239
|
|
@@ -234,25 +241,40 @@ module PEROBS
|
|
234
241
|
PEROBS.log.fatal "Cannot downgrade the FlatFile database from " +
|
235
242
|
"version #{version} to version #{VERSION}"
|
236
243
|
end
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
open
|
242
|
-
@flat_file.refresh
|
243
|
-
close
|
244
|
+
if version < 3
|
245
|
+
PEROBS.log.fatal "The upgrade of this version of the PEROBS database " +
|
246
|
+
"is not supported by this version of PEROBS. Please try an earlier " +
|
247
|
+
"version of PEROBS to upgrade the database before using this version."
|
244
248
|
end
|
245
249
|
|
246
|
-
#
|
247
|
-
#
|
248
|
-
|
250
|
+
# Version upgrades must be done one version number at a time. If the
|
251
|
+
# existing DB is multiple versions older than what the current PEROBS
|
252
|
+
# version expects than multiple upgrade runs will be needed.
|
253
|
+
while version < VERSION
|
254
|
+
if version == 3
|
255
|
+
PEROBS.log.warn "Updating FlatFileDB #{@db_dir} from version 3 to " +
|
256
|
+
"version 4 ..."
|
257
|
+
# Version 4 adds checksums for blob file headers. We have to convert
|
258
|
+
# the blob file to include the checksums.
|
259
|
+
FlatFile.insert_header_checksums(@db_dir)
|
260
|
+
open
|
261
|
+
@flat_file.regenerate_index_and_spaces
|
262
|
+
close
|
263
|
+
end
|
264
|
+
|
265
|
+
# After a successful upgrade change the version number in the DB as
|
266
|
+
# well.
|
249
267
|
write_version_file(version_file)
|
250
268
|
PEROBS.log.warn "Update of FlatFileDB '#{@db_dir}' from version " +
|
251
|
-
"#{version} to version #{
|
269
|
+
"#{version} to version #{version + 1} completed"
|
270
|
+
|
271
|
+
# Update version variable to new version.
|
272
|
+
version += 1
|
252
273
|
end
|
253
274
|
end
|
254
275
|
|
255
276
|
def write_version_file(version_file)
|
277
|
+
|
256
278
|
begin
|
257
279
|
RobustFile.write(version_file, VERSION)
|
258
280
|
rescue IOError => e
|
data/lib/perobs/Hash.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# = Hash.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
|
#
|
@@ -37,20 +37,36 @@ module PEROBS
|
|
37
37
|
# The implementation is largely a proxy around the standard Hash class. But
|
38
38
|
# all mutating methods must be re-implemented to convert PEROBS::Objects to
|
39
39
|
# POXReference objects and to register the object as modified with the
|
40
|
-
# cache.
|
40
|
+
# cache. However, it is not designed for large data sets as it always reads
|
41
|
+
# and writes the full data set for every access (unless it is cached). For
|
42
|
+
# data sets that could have more than a few hundred entries BigHash is the
|
43
|
+
# recommended alternative.
|
41
44
|
#
|
42
45
|
# We explicitely don't support Hash::store() as it conflicts with
|
43
46
|
# ObjectBase::store() method to access the store.
|
44
47
|
class Hash < ObjectBase
|
45
48
|
|
49
|
+
# These methods do not mutate the Hash. They only perform read
|
50
|
+
# operations and return a new PEROBS::Hash object.
|
51
|
+
([
|
52
|
+
:invert, :merge, :reject, :select
|
53
|
+
] + Enumerable.instance_methods).uniq.each do |method_sym|
|
54
|
+
# Create a wrapper method that passes the call to @data.
|
55
|
+
define_method(method_sym) do |*args, &block|
|
56
|
+
# Register the read operation with the cache.
|
57
|
+
@store.cache.cache_read(self)
|
58
|
+
@store.new(PEROBS::Hash, @data.send(method_sym, *args, &block))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
46
62
|
# These methods do not mutate the Hash. They only perform read
|
47
63
|
# operations.
|
48
64
|
([
|
49
65
|
:==, :[], :assoc, :compare_by_identity, :compare_by_identity?, :default,
|
50
66
|
:default_proc, :each, :each_key, :each_pair, :each_value, :empty?,
|
51
67
|
:eql?, :fetch, :flatten, :has_key?, :has_value?, :hash, :include?,
|
52
|
-
:
|
53
|
-
:pretty_print, :pretty_print_cycle, :rassoc, :
|
68
|
+
:key, :key?, :keys, :length, :member?,
|
69
|
+
:pretty_print, :pretty_print_cycle, :rassoc, :size,
|
54
70
|
:to_a, :to_h, :to_hash, :to_s, :value?, :values, :values_at
|
55
71
|
] + Enumerable.instance_methods).uniq.each do |method_sym|
|
56
72
|
# Create a wrapper method that passes the call to @data.
|
@@ -61,11 +77,22 @@ module PEROBS
|
|
61
77
|
end
|
62
78
|
end
|
63
79
|
|
64
|
-
# These methods mutate the Hash
|
80
|
+
# These methods mutate the Hash and return self
|
65
81
|
[
|
66
|
-
:
|
67
|
-
|
68
|
-
|
82
|
+
:clear, :keep_if, :merge!, :rehash, :reject!, :replace, :select!, :update
|
83
|
+
].each do |method_sym|
|
84
|
+
# Create a wrapper method that passes the call to @data.
|
85
|
+
define_method(method_sym) do |*args, &block|
|
86
|
+
# Register the write operation with the cache.
|
87
|
+
@store.cache.cache_write(self)
|
88
|
+
@data.send(method_sym, *args, &block)
|
89
|
+
myself
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# These methods mutate the Hash and return basic Ruby type objects.
|
94
|
+
[
|
95
|
+
:delete, :delete_if, :shift
|
69
96
|
].each do |method_sym|
|
70
97
|
# Create a wrapper method that passes the call to @data.
|
71
98
|
define_method(method_sym) do |*args, &block|
|
@@ -79,17 +106,35 @@ module PEROBS
|
|
79
106
|
# PEROBS users should never call this method or equivalents of derived
|
80
107
|
# methods directly.
|
81
108
|
# @param p [PEROBS::Handle] PEROBS handle
|
82
|
-
# @param default [
|
83
|
-
# stored for a specific key.
|
84
|
-
|
109
|
+
# @param default [Object] The default value that is returned when no value
|
110
|
+
# is stored for a specific key. The default must be of the
|
111
|
+
# supported type.
|
112
|
+
def initialize(p, default = nil, &block)
|
85
113
|
super(p)
|
86
|
-
|
87
|
-
|
114
|
+
_check_assignment_value(default)
|
115
|
+
if block_given?
|
116
|
+
@data = ::Hash.new(&block)
|
117
|
+
else
|
118
|
+
@data = ::Hash.new(default)
|
119
|
+
end
|
88
120
|
|
89
121
|
# Ensure that the newly created object will be pushed into the database.
|
90
122
|
@store.cache.cache_write(self)
|
91
123
|
end
|
92
124
|
|
125
|
+
# Proxy for assignment method.
|
126
|
+
def []=(key, value)
|
127
|
+
_check_assignment_value(value)
|
128
|
+
@store.cache.cache_write(self)
|
129
|
+
@data[key] = value
|
130
|
+
end
|
131
|
+
|
132
|
+
# Proxy for default= method.
|
133
|
+
def default=(value)
|
134
|
+
_check_assignment_value(value)
|
135
|
+
@data.default=(value)
|
136
|
+
end
|
137
|
+
|
93
138
|
# Return a list of all object IDs of all persistend objects that this Hash
|
94
139
|
# is referencing.
|
95
140
|
# @return [Array of Integer] IDs of referenced objects
|