perobs 4.4.0 → 4.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2c526c97aab15c09f8e8acbcb432203e7d60fef8c504df6ddb0b8f35459cca0
4
- data.tar.gz: ad077bb879c041289c7a474e87645064ff84203c674640aff59b5f23923ac1b7
3
+ metadata.gz: 90c77003da7bd628fa753bfe35918d8c702b433ac5113ba9fc206f7afa114f6c
4
+ data.tar.gz: c38f786cb10a040048b7d08b75c16baf034c116a3f9648ece3af7b50e7898446
5
5
  SHA512:
6
- metadata.gz: b86fc662ef8bbf623ee7da777f023a74e3db9502df18c45dcda9ce244982225aaec7e74ce25378147c807775765c57d801810ac16be01d2145227bb0642caa3b
7
- data.tar.gz: d0c5a79eb60a1221bc385a1fafbc77a1aaa1e47782b3ea27ca92f5f7c539804bc00a388fdddc1ab956d7805dbdd52d055f5cdd76a8bb155ec5ada4335b7b9175
6
+ metadata.gz: 1fea934c359190c3b171c99e4dbffb3af58ec2f9dd755eedc0acb7db556f0e2471bd3c527a2910e5d8f17cd59b3f1ca4079436bc80bd11ea5d6efa60f55a54e9
7
+ data.tar.gz: db71320a9672848a3e35088e7a8b3389278c987a1bea905336e3f8bfff6daeb27564724b6f9d681d364684a57ce8593021041626615dace155e1849b0944003b
@@ -135,27 +135,29 @@ module PEROBS
135
135
  node = self
136
136
 
137
137
  # Traverse the tree to find the right node to add or replace the value.
138
+ idx = index
138
139
  while node do
139
140
  # Once we have reached a leaf node we can insert or replace the value.
140
141
  if node.is_leaf?
141
- if index >= node.values.size
142
+ if idx >= node.values.size
142
143
  node.fatal "Set index (#{index}) larger than values array " +
143
- "(#{node.values.size})."
144
+ "(#{idx} >= #{node.values.size})."
144
145
  end
145
- node.values[index] = value
146
+ node.values[idx] = value
146
147
  return
147
148
  else
148
149
  # Descend into the right child node to add the value to.
149
- cidx = node.search_child_index(index)
150
- if (index -= node.offsets[cidx]) < 0
151
- node.fatal "Index (#{index}) became negative"
150
+ cidx = node.search_child_index(idx)
151
+ if (idx -= node.offsets[cidx]) < 0
152
+ node.fatal "Idx (#{idx}) became negative while looking for " +
153
+ "index #{index}."
152
154
  end
153
155
  node = node.children[cidx]
154
156
  end
155
157
  end
156
158
 
157
159
  node.fatal "Could not find proper node to set the value while " +
158
- "looking for index #{index}"
160
+ "looking for index #{index}."
159
161
  end
160
162
 
161
163
  # Insert the given value at the given index. All following values will be
@@ -811,7 +813,7 @@ module PEROBS
811
813
 
812
814
  # Print and log an error message for the node.
813
815
  def fatal(msg)
814
- msg = "Fatal error in BigArray node @#{@_id}: #{msg}\n" + @tree.to_s
816
+ msg = "Fatal error in BigArray node @#{@_id}: #{msg}\n"
815
817
  $stderr.puts msg
816
818
  PEROBS.log.fatal msg
817
819
  end
data/lib/perobs/Cache.rb CHANGED
@@ -165,10 +165,20 @@ module PEROBS
165
165
  # active, the write cache is flushed before the transaction is started.
166
166
  def begin_transaction
167
167
  if @transaction_stack.empty?
168
+ if @transaction_thread
169
+ PEROBS.log.fatal 'transaction_thread must be nil'
170
+ end
171
+ @transaction_thread = Thread.current
168
172
  # The new transaction is the top-level transaction. Flush the write
169
173
  # buffer to save the current state of all objects.
170
174
  flush
171
175
  else
176
+ # Nested transactions are currently only supported within the same
177
+ # thread. If we are in another thread, raise TransactionInOtherThread
178
+ # to pause the calling thread for a bit.
179
+ if @transaction_thread != Thread.current
180
+ raise TransactionInOtherThread
181
+ end
172
182
  # Save a copy of all objects that were modified during the enclosing
173
183
  # transaction.
174
184
  @transaction_stack.last.each do |id|
@@ -192,6 +202,7 @@ module PEROBS
192
202
  # into the backend storage.
193
203
  @transaction_stack.pop.each { |id| @transaction_objects[id]._sync }
194
204
  @transaction_objects = ::Hash.new
205
+ @transaction_thread = nil
195
206
  else
196
207
  # A nested transaction completed successfully. We add the list of
197
208
  # modified objects to the list of the enclosing transaction.
@@ -213,6 +224,7 @@ module PEROBS
213
224
  @transaction_stack.pop.each do |id|
214
225
  @transaction_objects[id]._restore(@transaction_stack.length)
215
226
  end
227
+ @transaction_thread = nil
216
228
  end
217
229
 
218
230
  # Clear all cached entries. You must call flush before calling this
@@ -224,6 +236,7 @@ module PEROBS
224
236
  @reads = ::Array.new(2 ** @bits)
225
237
  @writes = ::Array.new(2 ** @bits)
226
238
  @transaction_stack = ::Array.new
239
+ @transaction_thread = nil
227
240
  @transaction_objects = ::Hash.new
228
241
  end
229
242
 
data/lib/perobs/Log.rb CHANGED
@@ -42,6 +42,11 @@ module PEROBS
42
42
  # are caused by user error rather than program logic errors.
43
43
  class UsageError < StandardError ; end
44
44
 
45
+ # This is the Exception type that will be thrown when a transaction start
46
+ # failed because there is an ongoing transaction from another thread in
47
+ # progress.
48
+ class TransactionInOtherThread < StandardError ; end
49
+
45
50
  # The ILogger class is a singleton that provides a common logging mechanism
46
51
  # to all objects. It exposes essentially the same interface as the Logger
47
52
  # class, just as a singleton and extends fatal to raise an FatalError
data/lib/perobs/Store.rb CHANGED
@@ -455,7 +455,21 @@ module PEROBS
455
455
  # beginning of the transaction. The exception is passed on to the
456
456
  # enclosing scope, so you probably want to handle it accordingly.
457
457
  def transaction
458
- @lock.synchronize { @cache.begin_transaction }
458
+ transaction_not_started = true
459
+ while transaction_not_started do
460
+ begin
461
+ @lock.synchronize do
462
+ @cache.begin_transaction
463
+ # If we get to this point, the transaction was successfully
464
+ # started. We can exit the loop.
465
+ transaction_not_started = false
466
+ end
467
+ rescue TransactionInOtherThread
468
+ # sleep up to 50ms
469
+ sleep(rand(50) / 1000.0)
470
+ end
471
+ end
472
+
459
473
  begin
460
474
  yield if block_given?
461
475
  rescue => e
@@ -547,7 +561,7 @@ module PEROBS
547
561
  # Therefor no locking is needed or even possible. The GC can kick in at
548
562
  # any time and we could be anywhere in the code. So there is a small
549
563
  # risk for a race here, but it should not have any serious consequences.
550
- if @in_memory_objects[id] == ruby_object_id
564
+ if @in_memory_objects && @in_memory_objects[id] == ruby_object_id
551
565
  @in_memory_objects.delete(id)
552
566
  @stats[:collected_objects] += 1
553
567
  end
@@ -1,4 +1,4 @@
1
1
  module PEROBS
2
2
  # The version number
3
- VERSION = "4.4.0"
3
+ VERSION = "4.5.0"
4
4
  end
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.4.0
4
+ version: 4.5.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: 2022-02-05 00:00:00.000000000 Z
11
+ date: 2022-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler