rims 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29c18b0a88fc771e30319973c66baff76e8a4c6c9d7bc9c8c239dd78cf25b9c1
4
- data.tar.gz: d6e6f213bfea0ff8684de0b79e625face9f6ad22c6e6f94d23aaa900ca526805
3
+ metadata.gz: 299a57cf042b4a2854a5e040af070bbef170044d8cedbac0c4587559018deb45
4
+ data.tar.gz: f9f6f5a9654c9b84c7978c4d6aa15d6243150811ee7a70b6110ee1e40eb1753f
5
5
  SHA512:
6
- metadata.gz: ee07de390442b50d654e4290488be4ca99b72ee42ca6f4dcae6a745a43155d001284d8356a56ab4231ecd3dfc19a02965efd6fd007e5ec44c2f3128d9e296896
7
- data.tar.gz: 4519d3182df3ada8bf8a9cf6fa1a8d89673db9fdb7f500735fbf703e211dce4a851e5e9630976be3de89839eb79541aec75d87fc409a11560005d1b10a110064
6
+ metadata.gz: 8f7009d59c5a09874933e75a9cea109367fb8f1ef4f1a2718a19536df1055fe7f5e7a60392bc50cf14b964e103ee7c2aa43493b6bf6790c8cba8083605edf3f8
7
+ data.tar.gz: 78c978afee91b8f5a7ef769a55d4a62d5b2e138d7ef8c6d9ddf5942a997ea772dc1aa317915f72973c42e6b77b7a2cd7acce8a8bae6f9f402d19268524e3b8dc
data/ChangeLog CHANGED
@@ -1,8 +1,41 @@
1
+ 2019-03-06 TOKI Yoshinori <toki@freedom.ne.jp>
2
+
3
+ * RIMS version 0.2.2 is released.
4
+
5
+ 2019-03-03 TOKI Yoshinori <toki@freedom.ne.jp>
6
+
7
+ * lib/rims/test.rb: key-value store. closed error at test utility
8
+ is able to changed.
9
+
10
+ * test/test_cksum_kvs.rb, test/test_db.rb,
11
+ test/test_db_recovery.rb, test/test_lock.rb,
12
+ test/test_mail_store.rb, test/test_protocol_decoder.rb,
13
+ test/test_protocol_fetch.rb: check error messages at test.
14
+
15
+ * lib/rims/channel.rb: refactor channel for untagged server
16
+ response.
17
+
18
+ 2019-03-02 TOKI Yoshinori <toki@freedom.ne.jp>
19
+
20
+ * lib/rims/channel.rb, lib/rims/mail_store.rb: untagged servere
21
+ response mechanism is changed. server response queue is replaced
22
+ to server response channel.
23
+
24
+ 2019-02-26 TOKI Yoshinori <toki@freedom.ne.jp>
25
+
26
+ * lib/rims/mail_store.rb, lib/rims/pool.rb: generic object
27
+ pool. object's Lock has to be owned to the object that needs to
28
+ lock.
29
+
30
+ object pool no longer has object lock.
31
+ mail store now has read-write lock.
32
+ response queue bundle now has mutex lock.
33
+
1
34
  2019-02-18 TOKI Yoshinori <toki@freedom.ne.jp>
2
35
 
3
- * README.md, rims.gemspec: fixed for release to rubygems.
36
+ * RIMS version 0.2.1 is released.
4
37
 
5
- * lib/rims/version.rb : start to version 0.2.1.
38
+ * README.md, rims.gemspec: fixed for release to rubygems.
6
39
 
7
40
  2018-12-02 TOKI Yoshinori <toki@freedom.ne.jp>
8
41
 
@@ -1,22 +1,21 @@
1
- Copyright (c) 2013-2014 TOKI Yoshinori
1
+ The MIT License (MIT)
2
2
 
3
- MIT License
3
+ Copyright (c) 2013-2019 TOKI Yoshinori
4
4
 
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
12
11
 
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
15
14
 
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -33,6 +33,7 @@ module RIMS
33
33
  autoload :ReadLockTimeoutError, 'rims/lock'
34
34
  autoload :ReadWriteLock, 'rims/lock'
35
35
  autoload :Server, 'rims/server'
36
+ autoload :ServerResponseChannel, 'rims/channel'
36
37
  autoload :SyntaxError, 'rims/protocol'
37
38
  autoload :Test, 'rims/test'
38
39
  autoload :WriteLockError, 'rims/lock'
@@ -0,0 +1,157 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module RIMS
4
+ class ServerResponseChannel
5
+ def initialize
6
+ @mutex = Thread::Mutex.new
7
+ @channel = {}
8
+ end
9
+
10
+ def make_pub_sub_pair(mbox_id)
11
+ pub = ServerResponsePublisher.new(self, mbox_id)
12
+ sub = ServerResponseSubscriber.new(self, mbox_id, pub.pub_sub_pair_key)
13
+ return pub, attach(sub)
14
+ end
15
+
16
+ def attach(sub)
17
+ @mutex.synchronize{
18
+ @channel[sub.mbox_id] ||= {}
19
+ (@channel[sub.mbox_id].key? sub.pub_sub_pair_key) and raise ArgumentError, 'conflicted subscriber.'
20
+ @channel[sub.mbox_id][sub.pub_sub_pair_key] = sub
21
+ }
22
+
23
+ sub
24
+ end
25
+ private :attach
26
+
27
+ # do not call this method directly, call the following method
28
+ # instead.
29
+ # - ServerResponsePublisher#detach
30
+ # - ServerResponseSubscriber#detach
31
+ def detach(sub)
32
+ @mutex.synchronize{
33
+ ((@channel.key? sub.mbox_id) && (@channel[sub.mbox_id].key? sub.pub_sub_pair_key)) or raise ArgumentError, 'unregistered pub-sub pair.'
34
+ (@channel[sub.mbox_id][sub.pub_sub_pair_key] == sub) or raise 'internal error: mismatched subscriber.'
35
+
36
+ @channel[sub.mbox_id].delete(sub.pub_sub_pair_key)
37
+ if (@channel[sub.mbox_id].empty?) then
38
+ @channel.delete(sub.mbox_id)
39
+ end
40
+ }
41
+
42
+ nil
43
+ end
44
+
45
+ # do not call this method directly, call the following method
46
+ # instead.
47
+ # - ServerResponsePublisher#publish
48
+ def publish(mbox_id, pub_sub_pair_key, response_message)
49
+ @mutex.synchronize{
50
+ @channel[mbox_id].each_value do |sub|
51
+ if (sub.pub_sub_pair_key != pub_sub_pair_key) then
52
+ sub.publish(response_message)
53
+ end
54
+ end
55
+ }
56
+
57
+ nil
58
+ end
59
+ end
60
+
61
+ class ServerResponsePublisher
62
+ # do not call this method directly, call the following method
63
+ # instead.
64
+ # - ServerResponseChannel#make_pub_sub_pair
65
+ def initialize(channel, mbox_id)
66
+ @channel = channel
67
+ @mbox_id = mbox_id
68
+ end
69
+
70
+ attr_reader :mbox_id
71
+
72
+ def pub_sub_pair_key
73
+ object_id
74
+ end
75
+
76
+ def publish(response_message)
77
+ @channel or raise 'detached publisher.'
78
+ @channel.publish(@mbox_id, pub_sub_pair_key, response_message)
79
+ nil
80
+ end
81
+
82
+ def detach
83
+ @channel = nil
84
+ nil
85
+ end
86
+ end
87
+
88
+ class ServerResponseSubscriber
89
+ # do not call this method directly, call the following method
90
+ # instead.
91
+ # - ServerResponseChannel#make_pub_sub_pair
92
+ def initialize(channel, mbox_id, pub_sub_pair_key)
93
+ @channel = channel
94
+ @mbox_id = mbox_id
95
+ @pub_sub_pair_key = pub_sub_pair_key
96
+ @queue = Thread::Queue.new
97
+ end
98
+
99
+ attr_reader :mbox_id
100
+ attr_reader :pub_sub_pair_key
101
+
102
+ # do not call this method directly, call the following method
103
+ # instead.
104
+ # - ServerResponsePublisher#publish
105
+ def publish(response_message)
106
+ @queue.push(response_message)
107
+ nil
108
+ end
109
+
110
+ def detach
111
+ @channel.detach(self)
112
+ nil
113
+ end
114
+
115
+ def message?
116
+ ! @queue.empty?
117
+ end
118
+
119
+ def fetch
120
+ while (message?)
121
+ response_message = @queue.pop(true)
122
+ yield(response_message)
123
+ end
124
+
125
+ nil
126
+ end
127
+
128
+ def idle_wait
129
+ catch(:idle_interrupt) {
130
+ while (response_message = @queue.pop(false))
131
+ message_list = [ response_message ]
132
+ fetch{|next_response_message|
133
+ if (next_response_message) then
134
+ message_list << next_response_message
135
+ else
136
+ yield(message_list)
137
+ throw(:idle_interrupt)
138
+ end
139
+ }
140
+ yield(message_list)
141
+ end
142
+ }
143
+
144
+ nil
145
+ end
146
+
147
+ def idle_interrupt
148
+ @queue.push(nil)
149
+ nil
150
+ end
151
+ end
152
+ end
153
+
154
+ # Local Variables:
155
+ # mode: Ruby
156
+ # indent-tabs-mode: nil
157
+ # End:
@@ -706,11 +706,11 @@ module RIMS
706
706
  conf.help_option(add_banner: <<-'EOF'.chomp)
707
707
  passwd_plain.yml
708
708
  Example
709
- $ cat passwd_plain.yml
709
+ $ cat passwd_plain.yml
710
710
  - { user: foo, pass: open_sesame }
711
711
  - { user: "#postman", pass: "#postman" }
712
- $ rims pass-hash passwd_plain.yml >passwd_hash.yml
713
- $ cat passwd_hash.yml
712
+ $ rims pass-hash passwd_plain.yml >passwd_hash.yml
713
+ $ cat passwd_hash.yml
714
714
  ---
715
715
  - user: foo
716
716
  hash: SHA256:10000:YkslZucwN2QJ7LOft59Pgw==:d5dca9109cc787220eba65810e40165079ce3292407e74e8fbd5c6a8a9b12204
@@ -3,13 +3,16 @@
3
3
  require 'forwardable'
4
4
  require 'logger'
5
5
  require 'set'
6
- require 'thread'
7
6
 
8
7
  module RIMS
9
8
  class MailStore
9
+ extend Forwardable
10
+
10
11
  MSG_FLAG_NAMES = %w[ answered flagged deleted seen draft recent ].each{|n| n.freeze }.freeze
11
12
 
12
13
  def initialize(meta_db, msg_db, &mbox_db_factory) # :yields: mbox_id
14
+ @rw_lock = ReadWriteLock.new
15
+
13
16
  @meta_db = meta_db
14
17
  @msg_db = msg_db
15
18
  @mbox_db_factory = mbox_db_factory
@@ -26,11 +29,11 @@ module RIMS
26
29
  @meta_db.dirty = true
27
30
  end
28
31
 
29
- @server_response_queue_pool = RIMS::ObjectPool.new{|object_pool, mbox_id, object_lock|
30
- MailboxServerResponseQueueBundleHolder.new(object_pool, mbox_id, object_lock)
31
- }
32
+ @channel = ServerResponseChannel.new
32
33
  end
33
34
 
35
+ def_delegators :@rw_lock, :read_synchronize, :write_synchronize
36
+
34
37
  def get_mbox_db(mbox_id)
35
38
  if (@mbox_db.key? mbox_id) then
36
39
  @mbox_db[mbox_id] ||= @mbox_db_factory.call(mbox_id)
@@ -347,29 +350,30 @@ module RIMS
347
350
 
348
351
  def select_mbox(mbox_id)
349
352
  @meta_db.mbox_name(mbox_id) or raise "not found a mailbox: #{mbox_id}."
350
- MailFolder.new(mbox_id, self).attach_server_response_queue(@server_response_queue_pool)
353
+ MailFolder.new(mbox_id, self).attach(@channel)
351
354
  end
352
355
 
353
356
  def examine_mbox(mbox_id)
354
357
  @meta_db.mbox_name(mbox_id) or raise "not found a mailbox: #{mbox_id}."
355
- MailFolder.new(mbox_id, self, read_only: true).attach_server_response_queue(@server_response_queue_pool)
358
+ MailFolder.new(mbox_id, self, read_only: true).attach(@channel)
356
359
  end
357
360
 
358
361
  def self.build_pool(kvs_meta_open, kvs_text_open)
359
- RIMS::ObjectPool.new{|object_pool, unique_user_id, object_lock|
360
- RIMS::MailStoreHolder.build(object_pool, unique_user_id, object_lock, kvs_meta_open, kvs_text_open)
362
+ RIMS::ObjectPool.new{|object_pool, unique_user_id|
363
+ RIMS::MailStoreHolder.build(object_pool, unique_user_id, kvs_meta_open, kvs_text_open)
361
364
  }
362
365
  end
363
366
  end
364
367
 
365
368
  class MailFolder
369
+ extend Forwardable
370
+
366
371
  MessageStruct = Struct.new(:uid, :num)
367
372
 
368
373
  def initialize(mbox_id, mail_store, read_only: false)
369
374
  @mbox_id = mbox_id
370
375
  @mail_store = mail_store
371
376
  @read_only = read_only
372
- @mail_folder_key = object_id
373
377
 
374
378
  # late loding
375
379
  @cnum = nil
@@ -377,50 +381,16 @@ module RIMS
377
381
  @uid_map = nil
378
382
  end
379
383
 
380
- def attach_server_response_queue(server_response_queue_pool)
381
- @server_response_queue_bundle = server_response_queue_pool.get(@mbox_id)
382
- @server_response_queue = @server_response_queue_bundle.attach_queue(@mail_folder_key)
383
- self
384
- end
385
-
386
- def server_response_multicast_push(server_response_message)
387
- @server_response_queue_bundle.multicast_push(server_response_message, @mail_folder_key)
388
- self
389
- end
390
-
391
- def server_response?
392
- ! @server_response_queue.empty?
393
- end
394
-
395
- def server_response_fetch
396
- while (server_response?)
397
- server_response_message = @server_response_queue.pop(true)
398
- yield(server_response_message)
399
- end
400
- self
401
- end
402
-
403
- def server_response_idle_wait
404
- catch(:server_response_idle_wait_interrupt) {
405
- while (server_response_message = @server_response_queue.pop(false))
406
- server_response_list = [ server_response_message ]
407
- server_response_fetch{|next_response_message|
408
- if (next_response_message) then
409
- server_response_list.push(next_response_message)
410
- else
411
- yield(server_response_list)
412
- throw(:server_response_idle_wait_interrupt)
413
- end
414
- }
415
- yield(server_response_list)
416
- end
417
- }
384
+ def attach(server_response_channel)
385
+ @pub, @sub = server_response_channel.make_pub_sub_pair(@mbox_id)
418
386
  self
419
387
  end
420
388
 
421
- def server_response_idle_interrupt
422
- @server_response_queue.push(nil)
423
- end
389
+ def_delegator :@pub, :publish, :server_response_multicast_push
390
+ def_delegator :@sub, :message?, :server_response?
391
+ def_delegator :@sub, :fetch, :server_response_fetch
392
+ def_delegator :@sub, :idle_wait, :server_response_idle_wait
393
+ def_delegator :@sub, :idle_interrupt, :server_response_idle_interrupt
424
394
 
425
395
  def reload
426
396
  @cnum = @mail_store.cnum
@@ -532,11 +502,8 @@ module RIMS
532
502
  end
533
503
  end
534
504
  @mail_store = nil
535
-
536
- @server_response_queue_bundle.detach_queue(@mail_folder_key)
537
- @server_response_queue_bundle.return_pool
538
- @server_response_queue_bundle = nil
539
-
505
+ @pub.detach
506
+ @sub.detach
540
507
  self
541
508
  end
542
509
 
@@ -596,7 +563,7 @@ module RIMS
596
563
  class MailStoreHolder < ObjectPool::ObjectHolder
597
564
  extend Forwardable
598
565
 
599
- def self.build(object_pool, unique_user_id, object_lock, kvs_meta_open, kvs_text_open)
566
+ def self.build(object_pool, unique_user_id, kvs_meta_open, kvs_text_open)
600
567
  kvs_build = proc{|kvs_open, db_name|
601
568
  kvs_open.call(MAILBOX_DATA_STRUCTURE_VERSION, unique_user_id, db_name)
602
569
  }
@@ -607,54 +574,23 @@ module RIMS
607
574
  }
608
575
  mail_store.add_mbox('INBOX') unless mail_store.mbox_id('INBOX')
609
576
 
610
- new(object_pool, unique_user_id, object_lock, mail_store)
577
+ new(object_pool, unique_user_id, mail_store)
611
578
  end
612
579
 
613
- def initialize(object_pool, unique_user_id, object_lock, mail_store)
580
+ def initialize(object_pool, unique_user_id, mail_store)
614
581
  super(object_pool, unique_user_id)
615
- @object_lock = object_lock
616
582
  @mail_store = mail_store
617
583
  end
618
584
 
619
585
  alias unique_user_id object_key
620
586
  attr_reader :mail_store
621
587
 
622
- def_delegator :@object_lock, :read_synchronize
623
- def_delegator :@object_lock, :write_synchronize
588
+ def_delegators :@mail_store, :read_synchronize, :write_synchronize
624
589
 
625
590
  def object_destroy
626
591
  @mail_store.close
627
592
  end
628
593
  end
629
-
630
- class MailboxServerResponseQueueBundleHolder < ObjectPool::ObjectHolder
631
- def initialize(object_pool, mbox_id, object_lock)
632
- super(object_pool, mbox_id)
633
- @object_lock = object_lock
634
- @queue_map = Hash.new{|h, k| h[k] = Thread::Queue.new }
635
- end
636
-
637
- alias mbox_id object_id
638
-
639
- def attach_queue(mail_folder_key)
640
- @object_lock.write_synchronize{ @queue_map[mail_folder_key] }
641
- end
642
-
643
- def detach_queue(mail_folder_key)
644
- @object_lock.write_synchronize{ @queue_map.delete(mail_folder_key) } or raise "not found a queue at mail folder key: #{mail_folder_key}"
645
- self
646
- end
647
-
648
- def multicast_push(server_response_message, this_mail_folder_key)
649
- @object_lock.read_synchronize{
650
- for mail_folder_key, queue in @queue_map
651
- next if (mail_folder_key == this_mail_folder_key)
652
- queue.push(server_response_message)
653
- end
654
- }
655
- self
656
- end
657
- end
658
594
  end
659
595
 
660
596
  # Local Variables: