rims 0.2.1 → 0.2.2
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/ChangeLog +35 -2
- data/LICENSE.txt +17 -18
- data/lib/rims.rb +1 -0
- data/lib/rims/channel.rb +157 -0
- data/lib/rims/cmd.rb +3 -3
- data/lib/rims/mail_store.rb +26 -90
- data/lib/rims/pool.rb +15 -18
- data/lib/rims/protocol/decoder.rb +4 -4
- data/lib/rims/protocol/parser.rb +2 -2
- data/lib/rims/test.rb +39 -7
- data/lib/rims/version.rb +1 -1
- data/test/test_channel.rb +131 -0
- data/test/test_cksum_kvs.rb +4 -2
- data/test/test_config.rb +1 -1
- data/test/test_db.rb +10 -5
- data/test/test_db_recovery.rb +6 -3
- data/test/test_lock.rb +4 -2
- data/test/test_mail_store.rb +22 -6
- data/test/test_protocol_decoder.rb +2 -1
- data/test/test_protocol_fetch.rb +7 -3
- data/test/test_protocol_search.rb +66 -53
- data/test/test_rfc822.rb +1 -1
- metadata +5 -2
data/lib/rims/pool.rb
CHANGED
@@ -14,8 +14,8 @@ module RIMS
|
|
14
14
|
end
|
15
15
|
|
16
16
|
# optional block is called when a mail store is closed.
|
17
|
-
def return_pool(
|
18
|
-
@object_pool.put(self,
|
17
|
+
def return_pool(&block) # yields:
|
18
|
+
@object_pool.put(self, &block)
|
19
19
|
nil
|
20
20
|
end
|
21
21
|
end
|
@@ -35,27 +35,25 @@ module RIMS
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def initialize(&object_factory) # yields: object_pool, object_key, object_lock
|
38
|
+
@mutex = Thread::Mutex.new
|
38
39
|
@object_factory = object_factory
|
39
|
-
@
|
40
|
-
@pool_lock = Mutex.new
|
41
|
-
@object_lock_map = Hash.new{|hash, key| hash[key] = ReadWriteLock.new }
|
40
|
+
@pool = {}
|
42
41
|
end
|
43
42
|
|
44
43
|
def empty?
|
45
|
-
@
|
44
|
+
@mutex.synchronize{ @pool.empty? }
|
46
45
|
end
|
47
46
|
|
48
47
|
# optional block is called when a new object is added to an object pool.
|
49
|
-
def get(object_key
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
ref_count = @pool_lock.synchronize{ @pool_map[object_key] }
|
48
|
+
def get(object_key) # yields:
|
49
|
+
@mutex.synchronize{
|
50
|
+
if (@pool.key? object_key) then
|
51
|
+
ref_count = @pool[object_key]
|
54
52
|
else
|
55
53
|
yield if block_given?
|
56
|
-
object_holder = @object_factory.call(self, object_key
|
54
|
+
object_holder = @object_factory.call(self, object_key)
|
57
55
|
ref_count = ReferenceCount.new(0, object_holder)
|
58
|
-
@
|
56
|
+
@pool[object_key] = ref_count
|
59
57
|
end
|
60
58
|
ref_count.count >= 0 or raise 'internal error'
|
61
59
|
ref_count.count += 1
|
@@ -64,15 +62,14 @@ module RIMS
|
|
64
62
|
end
|
65
63
|
|
66
64
|
# optional block is called when an object is deleted from an object pool.
|
67
|
-
def put(object_holder
|
68
|
-
|
69
|
-
|
70
|
-
ref_count = @pool_lock.synchronize{ @pool_map[object_holder.object_key] } or raise 'internal error'
|
65
|
+
def put(object_holder) # yields:
|
66
|
+
@mutex.synchronize{
|
67
|
+
ref_count = @pool[object_holder.object_key] or raise 'internal error'
|
71
68
|
ref_count.object_holder.equal? object_holder or raise 'internal error'
|
72
69
|
ref_count.count > 0 or raise 'internal error'
|
73
70
|
ref_count.count -= 1
|
74
71
|
if (ref_count.count == 0) then
|
75
|
-
@
|
72
|
+
@pool.delete(object_holder.object_key)
|
76
73
|
ref_count.object_destroy
|
77
74
|
yield if block_given?
|
78
75
|
end
|
@@ -156,7 +156,7 @@ module RIMS
|
|
156
156
|
@logger.error($!)
|
157
157
|
res << "#{tag} BAD client command syntax error\r\n"
|
158
158
|
rescue
|
159
|
-
raise if ($!.name =~ /AssertionFailedError/)
|
159
|
+
raise if ($!.class.name =~ /AssertionFailedError/)
|
160
160
|
@logger.error('internal server error.')
|
161
161
|
@logger.error($!)
|
162
162
|
res << "#{tag} BAD internal server error\r\n"
|
@@ -206,7 +206,7 @@ module RIMS
|
|
206
206
|
unique_user_id = Authentication.unique_user_id(username)
|
207
207
|
logger.debug("unique user ID: #{username} -> #{unique_user_id}") if logger.debug?
|
208
208
|
|
209
|
-
mail_store_holder = mail_store_pool.get(unique_user_id
|
209
|
+
mail_store_holder = mail_store_pool.get(unique_user_id) {
|
210
210
|
logger.info("open mail store: #{unique_user_id} [ #{username} ]")
|
211
211
|
}
|
212
212
|
|
@@ -510,7 +510,7 @@ module RIMS
|
|
510
510
|
end
|
511
511
|
tmp_mail_store_holder = @mail_store_holder
|
512
512
|
ReadWriteLock.write_lock_timeout_detach(@cleanup_write_lock_timeout_seconds, @write_lock_timeout_seconds, logger: @logger) {|timeout_seconds|
|
513
|
-
tmp_mail_store_holder.return_pool
|
513
|
+
tmp_mail_store_holder.return_pool{
|
514
514
|
@logger.info("close mail store: #{tmp_mail_store_holder.unique_user_id}")
|
515
515
|
}
|
516
516
|
}
|
@@ -1272,7 +1272,7 @@ module RIMS
|
|
1272
1272
|
@last_user_cache_key_username = nil
|
1273
1273
|
@last_user_cache_value_mail_store_holder = nil
|
1274
1274
|
ReadWriteLock.write_lock_timeout_detach(@cleanup_write_lock_timeout_seconds, @write_lock_timeout_seconds, logger: @logger) {|timeout_seconds|
|
1275
|
-
mail_store_holder.return_pool
|
1275
|
+
mail_store_holder.return_pool{
|
1276
1276
|
@logger.info("close cached mail store to deliver message: #{mail_store_holder.unique_user_id}")
|
1277
1277
|
}
|
1278
1278
|
}
|
data/lib/rims/protocol/parser.rb
CHANGED
@@ -631,9 +631,9 @@ module RIMS
|
|
631
631
|
unless (search_key.empty?) then
|
632
632
|
search_key = search_key.dup
|
633
633
|
factory = fetch_next_node(search_key)
|
634
|
-
|
634
|
+
_cond = factory.call(parse_cached(search_key))
|
635
635
|
else
|
636
|
-
|
636
|
+
_cond = end_of_cond
|
637
637
|
end
|
638
638
|
end
|
639
639
|
private :parse_cached
|
data/lib/rims/test.rb
CHANGED
@@ -235,6 +235,38 @@ EOF
|
|
235
235
|
end
|
236
236
|
end
|
237
237
|
|
238
|
+
def db_closed_error
|
239
|
+
RuntimeError
|
240
|
+
end
|
241
|
+
|
242
|
+
def db_closed_fetch_error
|
243
|
+
db_closed_error
|
244
|
+
end
|
245
|
+
|
246
|
+
def db_closed_store_error
|
247
|
+
db_closed_error
|
248
|
+
end
|
249
|
+
|
250
|
+
def db_closed_delete_error
|
251
|
+
db_closed_error
|
252
|
+
end
|
253
|
+
|
254
|
+
def db_closed_key_error
|
255
|
+
db_closed_error
|
256
|
+
end
|
257
|
+
|
258
|
+
def db_closed_each_key_error
|
259
|
+
db_closed_error
|
260
|
+
end
|
261
|
+
|
262
|
+
def db_closed_each_value_error
|
263
|
+
db_closed_error
|
264
|
+
end
|
265
|
+
|
266
|
+
def db_closed_each_pair_error
|
267
|
+
db_closed_error
|
268
|
+
end
|
269
|
+
|
238
270
|
def setup
|
239
271
|
@base_dir = 'kvs_test_dir'
|
240
272
|
FileUtils.mkdir_p(@base_dir)
|
@@ -336,13 +368,13 @@ EOF
|
|
336
368
|
assert_equal(true, db_closed?)
|
337
369
|
|
338
370
|
# closed exception
|
339
|
-
assert_raise(
|
340
|
-
assert_raise(
|
341
|
-
assert_raise(
|
342
|
-
assert_raise(
|
343
|
-
assert_raise(
|
344
|
-
assert_raise(
|
345
|
-
assert_raise(
|
371
|
+
assert_raise(db_closed_fetch_error) { @kvs['foo'] }
|
372
|
+
assert_raise(db_closed_store_error) { @kvs['foo'] = 'apple' }
|
373
|
+
assert_raise(db_closed_delete_error) { @kvs.delete('foo') }
|
374
|
+
assert_raise(db_closed_key_error) { @kvs.key? 'foo' }
|
375
|
+
assert_raise(db_closed_each_key_error) { @kvs.each_key.to_a }
|
376
|
+
assert_raise(db_closed_each_value_error) { @kvs.each_value.to_a }
|
377
|
+
assert_raise(db_closed_each_pair_error) { @kvs.each_pair.to_a }
|
346
378
|
end
|
347
379
|
end
|
348
380
|
|
data/lib/rims/version.rb
CHANGED
@@ -0,0 +1,131 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'rims'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
module RIMS::Test
|
7
|
+
class ServerResponseChannelTest < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@channel = RIMS::ServerResponseChannel.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_pub_sub_fetch_message
|
13
|
+
pub1, sub1 = @channel.make_pub_sub_pair(0)
|
14
|
+
pub2, sub2 = @channel.make_pub_sub_pair(0)
|
15
|
+
pub3, sub3 = @channel.make_pub_sub_pair(0)
|
16
|
+
|
17
|
+
pub1.publish('msg1')
|
18
|
+
assert_equal(false, sub1.message?)
|
19
|
+
assert_equal(true, sub2.message?)
|
20
|
+
assert_equal(true, sub3.message?)
|
21
|
+
|
22
|
+
pub2.publish('msg2')
|
23
|
+
assert_equal(true, sub1.message?)
|
24
|
+
assert_equal(true, sub2.message?)
|
25
|
+
assert_equal(true, sub3.message?)
|
26
|
+
|
27
|
+
pub3.publish('msg3')
|
28
|
+
assert_equal(true, sub1.message?)
|
29
|
+
assert_equal(true, sub2.message?)
|
30
|
+
assert_equal(true, sub3.message?)
|
31
|
+
|
32
|
+
assert_equal(%w[ msg2 msg3 ], sub1.enum_for(:fetch).to_a)
|
33
|
+
assert_equal(%w[ msg1 msg3 ], sub2.enum_for(:fetch).to_a)
|
34
|
+
assert_equal(%w[ msg1 msg2 ], sub3.enum_for(:fetch).to_a)
|
35
|
+
|
36
|
+
assert_equal(false, sub1.message?)
|
37
|
+
assert_equal(false, sub2.message?)
|
38
|
+
assert_equal(false, sub3.message?)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_pub_sub_fetch_no_message
|
42
|
+
_, sub = @channel.make_pub_sub_pair(0)
|
43
|
+
assert_equal(false, sub.message?)
|
44
|
+
assert_equal([], sub.enum_for(:fetch).to_a)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_pub_sub_detach
|
48
|
+
pub1, sub1 = @channel.make_pub_sub_pair(0)
|
49
|
+
pub2, sub2 = @channel.make_pub_sub_pair(0)
|
50
|
+
pub3, sub3 = @channel.make_pub_sub_pair(0)
|
51
|
+
|
52
|
+
pub3.detach
|
53
|
+
sub3.detach
|
54
|
+
|
55
|
+
pub1.publish('msg1')
|
56
|
+
pub2.publish('msg2')
|
57
|
+
|
58
|
+
error = assert_raise(RuntimeError) { pub3.publish('msg3') }
|
59
|
+
assert_match(/detached/, error.message)
|
60
|
+
|
61
|
+
assert_equal(%w[ msg2 ], sub1.enum_for(:fetch).to_a)
|
62
|
+
assert_equal(%w[ msg1 ], sub2.enum_for(:fetch).to_a)
|
63
|
+
assert_equal([], sub3.enum_for(:fetch).to_a)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_pub_sub_different_mailboxes
|
67
|
+
mbox0_pub1, mbox0_sub1 = @channel.make_pub_sub_pair(0)
|
68
|
+
mbox0_pub2, mbox0_sub2 = @channel.make_pub_sub_pair(0)
|
69
|
+
mbox1_pub1, mbox1_sub1 = @channel.make_pub_sub_pair(1)
|
70
|
+
mbox1_pub2, mbox1_sub2 = @channel.make_pub_sub_pair(1)
|
71
|
+
|
72
|
+
mbox0_pub1.publish('mbox0:msg1')
|
73
|
+
mbox0_pub2.publish('mbox0:msg2')
|
74
|
+
|
75
|
+
assert_equal(%w[ mbox0:msg2 ], mbox0_sub1.enum_for(:fetch).to_a)
|
76
|
+
assert_equal(%w[ mbox0:msg1 ], mbox0_sub2.enum_for(:fetch).to_a)
|
77
|
+
assert_equal([], mbox1_sub1.enum_for(:fetch).to_a)
|
78
|
+
assert_equal([], mbox1_sub2.enum_for(:fetch).to_a)
|
79
|
+
|
80
|
+
mbox1_pub1.publish('mbox1:msg1')
|
81
|
+
mbox1_pub2.publish('mbox1:msg2')
|
82
|
+
|
83
|
+
assert_equal([], mbox0_sub1.enum_for(:fetch).to_a)
|
84
|
+
assert_equal([], mbox0_sub2.enum_for(:fetch).to_a)
|
85
|
+
assert_equal(%w[ mbox1:msg2 ], mbox1_sub1.enum_for(:fetch).to_a)
|
86
|
+
assert_equal(%w[ mbox1:msg1 ], mbox1_sub2.enum_for(:fetch).to_a)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_pub_sub_idle
|
90
|
+
pub, _ = @channel.make_pub_sub_pair(0)
|
91
|
+
_, sub = @channel.make_pub_sub_pair(0)
|
92
|
+
|
93
|
+
pub.publish('msg1')
|
94
|
+
sub.idle_interrupt
|
95
|
+
assert_equal([ %w[ msg1 ] ], sub.enum_for(:idle_wait).to_a)
|
96
|
+
|
97
|
+
pub.publish('msg2')
|
98
|
+
pub.publish('msg3')
|
99
|
+
sub.idle_interrupt
|
100
|
+
assert_equal([ %w[ msg2 msg3 ] ], sub.enum_for(:idle_wait).to_a)
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_pub_sub_idle_chunks
|
104
|
+
pub, _ = @channel.make_pub_sub_pair(0)
|
105
|
+
_, sub = @channel.make_pub_sub_pair(0)
|
106
|
+
|
107
|
+
t = Thread.new{ sub.enum_for(:idle_wait).to_a }
|
108
|
+
|
109
|
+
pub.publish('msg1')
|
110
|
+
t.wakeup
|
111
|
+
sleep(0.1)
|
112
|
+
|
113
|
+
pub.publish('msg2')
|
114
|
+
pub.publish('msg3')
|
115
|
+
sub.idle_interrupt
|
116
|
+
|
117
|
+
assert_equal([ %w[ msg1 ], %w[ msg2 msg3 ] ], t.value)
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_pub_sub_idle_no_message
|
121
|
+
_, sub = @channel.make_pub_sub_pair(0)
|
122
|
+
sub.idle_interrupt
|
123
|
+
assert_equal([], sub.enum_for(:idle_wait).to_a)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Local Variables:
|
129
|
+
# mode: Ruby
|
130
|
+
# indent-tabs-mode: nil
|
131
|
+
# End:
|
data/test/test_cksum_kvs.rb
CHANGED
@@ -107,10 +107,12 @@ module RIMS::Test
|
|
107
107
|
|
108
108
|
s = @db['foo']
|
109
109
|
@db['foo'] = s.chop
|
110
|
-
assert_raise(RuntimeError) { @kvs['foo'] }
|
110
|
+
error = assert_raise(RuntimeError) { @kvs['foo'] }
|
111
|
+
assert_match(/checksum error/, error.message)
|
111
112
|
|
112
113
|
@db['foo'] = 'Hello world.'
|
113
|
-
assert_raise(RuntimeError) { @kvs['foo'] }
|
114
|
+
error = assert_raise(RuntimeError) { @kvs['foo'] }
|
115
|
+
assert_match(/checksum format error/, error.message)
|
114
116
|
end
|
115
117
|
end
|
116
118
|
end
|
data/test/test_config.rb
CHANGED
@@ -108,7 +108,7 @@ module RIMS::Test
|
|
108
108
|
begin
|
109
109
|
assert_config(load_libraries: %w[ prime ]) {|conf|
|
110
110
|
conf.setup_load_libraries
|
111
|
-
assert($LOADED_FEATURES.any?{|name| name =~ /prime/})
|
111
|
+
assert($LOADED_FEATURES.any?{|name| name =~ /prime/})
|
112
112
|
}
|
113
113
|
rescue
|
114
114
|
exit!(1)
|
data/test/test_db.rb
CHANGED
@@ -448,7 +448,8 @@ module RIMS::Test
|
|
448
448
|
assert_equal(false, (@db.msg_exist? 1))
|
449
449
|
assert_equal(true, (@db.msg_exist? 2))
|
450
450
|
|
451
|
-
assert_raise(RuntimeError) { @db.del_msg(1) }
|
451
|
+
error = assert_raise(RuntimeError) { @db.del_msg(1) }
|
452
|
+
assert_match(/not found a message text/, error.message)
|
452
453
|
end
|
453
454
|
end
|
454
455
|
|
@@ -531,8 +532,10 @@ module RIMS::Test
|
|
531
532
|
assert_equal(deleted, @db.msg_flag_deleted(uid))
|
532
533
|
end
|
533
534
|
|
534
|
-
assert_raise(RuntimeError) { @db.expunge_msg(1) }
|
535
|
-
|
535
|
+
error = assert_raise(RuntimeError) { @db.expunge_msg(1) }
|
536
|
+
assert_match(/not found a message uid/, error.message)
|
537
|
+
error = assert_raise(RuntimeError) { @db.expunge_msg(2) }
|
538
|
+
assert_match(/not deleted flag/, error.message)
|
536
539
|
end
|
537
540
|
end
|
538
541
|
|
@@ -572,12 +575,13 @@ module RIMS::Test
|
|
572
575
|
@cksum_kvs['baz'] = 'orange'
|
573
576
|
|
574
577
|
count = 0
|
575
|
-
assert_raise(RuntimeError) {
|
578
|
+
error = assert_raise(RuntimeError) {
|
576
579
|
@db.test_read_all{|read_error|
|
577
580
|
assert_kind_of(RuntimeError, read_error)
|
578
581
|
count += 1
|
579
582
|
}
|
580
583
|
}
|
584
|
+
assert_match(/checksum format error/, error.message)
|
581
585
|
assert_equal(1, count)
|
582
586
|
|
583
587
|
@cksum_kvs['foo'] = 'apple'; @kvs['foo'] = 'apple'
|
@@ -585,12 +589,13 @@ module RIMS::Test
|
|
585
589
|
@cksum_kvs['baz'] = 'orange'; @kvs['baz'] = 'orange'
|
586
590
|
|
587
591
|
count = 0
|
588
|
-
assert_raise(RuntimeError) {
|
592
|
+
error = assert_raise(RuntimeError) {
|
589
593
|
@db.test_read_all{|read_error|
|
590
594
|
assert_kind_of(RuntimeError, read_error)
|
591
595
|
count += 1
|
592
596
|
}
|
593
597
|
}
|
598
|
+
assert_match(/checksum format error/, error.message)
|
594
599
|
assert_equal(2, count)
|
595
600
|
end
|
596
601
|
end
|
data/test/test_db_recovery.rb
CHANGED
@@ -73,7 +73,8 @@ module RIMS::Test
|
|
73
73
|
|
74
74
|
@kvs['meta'].delete('msg_id2date-1')
|
75
75
|
assert_instance_of(Time, @meta_db.msg_date(0))
|
76
|
-
assert_raise(RuntimeError) { @meta_db.msg_date(1) }
|
76
|
+
error = assert_raise(RuntimeError) { @meta_db.msg_date(1) }
|
77
|
+
assert_match(/not found a message date/, error.message)
|
77
78
|
assert_instance_of(Time, @meta_db.msg_date(2))
|
78
79
|
|
79
80
|
@meta_db.recovery_phase1_msg_scan(@msg_db, logger: @logger)
|
@@ -635,7 +636,8 @@ module RIMS::Test
|
|
635
636
|
|
636
637
|
# recovery phase 2
|
637
638
|
assert_equal({}, @meta_db.msg_mbox_uid_mapping(3))
|
638
|
-
assert_raise(RuntimeError) { @meta_db.msg_date(3) }
|
639
|
+
error = assert_raise(RuntimeError) { @meta_db.msg_date(3) }
|
640
|
+
assert_match(/not found a message date/, error.message)
|
639
641
|
|
640
642
|
# recovery phase 3
|
641
643
|
assert_equal(5, @meta_db.uidvalidity)
|
@@ -672,7 +674,8 @@ module RIMS::Test
|
|
672
674
|
# recovery phase 1,8
|
673
675
|
@msg_db.add_msg(3, 'apple')
|
674
676
|
assert_equal({}, @meta_db.msg_mbox_uid_mapping(3))
|
675
|
-
assert_raise(RuntimeError) { @meta_db.msg_date(3) }
|
677
|
+
error = assert_raise(RuntimeError) { @meta_db.msg_date(3) }
|
678
|
+
assert_match(/not found a message date/, error.message)
|
676
679
|
|
677
680
|
# recovery phase 2,5,8
|
678
681
|
mbox_uid_map = Marshal.load(@kvs['meta']['msg_id2mbox-0'])
|
data/test/test_lock.rb
CHANGED
@@ -34,19 +34,21 @@ module RIMS::Test
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def test_read_lock_timeout
|
37
|
-
assert_raise(RIMS::ReadLockTimeoutError) {
|
37
|
+
error = assert_raise(RIMS::ReadLockTimeoutError) {
|
38
38
|
@lock.write_synchronize{
|
39
39
|
@lock.read_synchronize(0) {}
|
40
40
|
}
|
41
41
|
}
|
42
|
+
assert_equal('read-lock wait timeout', error.message)
|
42
43
|
end
|
43
44
|
|
44
45
|
def test_write_lock_timeout
|
45
|
-
assert_raise(RIMS::WriteLockTimeoutError) {
|
46
|
+
error = assert_raise(RIMS::WriteLockTimeoutError) {
|
46
47
|
@lock.write_synchronize{
|
47
48
|
@lock.write_synchronize(0) {}
|
48
49
|
}
|
49
50
|
}
|
51
|
+
assert_equal('write-lock wait timeout', error.message)
|
50
52
|
end
|
51
53
|
|
52
54
|
def calculate_threa_work_seconds
|