fmq 0.1.1 → 0.2.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.
@@ -0,0 +1,75 @@
1
+ #
2
+ # Copyright (c) 2008 Vincent Landgraf
3
+ #
4
+ # This file is part of the Free Message Queue.
5
+ #
6
+ # Free Message Queue is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Free Message Queue is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Free Message Queue. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+ module FreeMessageQueue
20
+ # This is the default message implementation in the queue system
21
+ class Message
22
+ attr_accessor :next, # reference to next Message if there is one
23
+ :payload, # the content itself
24
+ :created_at, # when came the message into the system
25
+ :content_type, # the content type of the message
26
+ :option # options hash (META-DATA) for the message
27
+
28
+ # Create a message item. The payload is often just a string
29
+ def initialize(payload, content_type = "text/plain", created_at = Time.new)
30
+ @payload = payload
31
+ @created_at = created_at
32
+ @content_type = content_type
33
+ @option = {}
34
+ end
35
+
36
+ # Aize of item in bytes
37
+ def bytes
38
+ @payload.size
39
+ end
40
+ end
41
+
42
+ # every queue has to have this interface
43
+ class BaseQueue
44
+ # QueueManager refrence
45
+ attr_accessor :manager
46
+
47
+ attr_reader :bytes, # the amount of space that is used by all messages in the queue
48
+ :size # the size / depp of the queue = count of messages
49
+
50
+ def initialize(manager)
51
+ @manager = manager
52
+ @bytes = 0
53
+ @size = 0
54
+ end
55
+
56
+ # returns true if there is no message in the queue
57
+ def empty?
58
+ size == 0
59
+ end
60
+
61
+ protected
62
+
63
+ # update queue size and memory usage (add one messge)
64
+ def add_message(bytes)
65
+ @size += 1
66
+ @bytes += bytes
67
+ end
68
+
69
+ # update queue size and memory usage (remove one messge)
70
+ def remove_message(bytes)
71
+ @size -= 1
72
+ @bytes -= bytes
73
+ end
74
+ end
75
+ end
@@ -16,6 +16,8 @@
16
16
  # You should have received a copy of the GNU General Public License
17
17
  # along with Free Message Queue. If not, see <http://www.gnu.org/licenses/>.
18
18
  #
19
+ require File.dirname(__FILE__) + '/base'
20
+
19
21
  module FreeMessageQueue
20
22
  # This queue returns everytime the same file. This is useful during debugging or
21
23
  # to serve the admin page.
@@ -31,30 +33,15 @@ module FreeMessageQueue
31
33
  # content-type: text/html
32
34
  #
33
35
  # *NOTE* the put method is not implemented in this queue. It is a poll only queue.
34
- class FileQueue
35
- # QueueManager refrence
36
- attr_accessor :manager
37
-
38
- # Bytes are -1 at startup but fill after first poll. Size is allways 1 message
39
- attr_reader :bytes, :size
40
-
41
- def initialize
42
- # there is always one message (the file) in the queue
43
- @bytes = -1
44
- @size = 1
45
- end
46
-
36
+ class FileQueue < BaseQueue
47
37
  # Return the file and content type
48
38
  def poll()
49
- item = OpenStruct.new
50
-
51
39
  f = open(@file_path, "rb")
52
- item.data = f.read
53
- @bytes = item.data.size
40
+ file_content = f.read
54
41
  f.close
55
42
 
56
- item.content_type = @content_type
57
- item
43
+ @bytes = file_content.size
44
+ Message.new(file_content, @content_type)
58
45
  end
59
46
 
60
47
  # *CONFIGURATION* *OPTION*
@@ -16,7 +16,7 @@
16
16
  # You should have received a copy of the GNU General Public License
17
17
  # along with Free Message Queue. If not, see <http://www.gnu.org/licenses/>.
18
18
  #
19
- require "ostruct"
19
+ require File.dirname(__FILE__) + '/base'
20
20
 
21
21
  module FreeMessageQueue
22
22
  # This queue returns sends one message to several queues at a time.
@@ -30,23 +30,18 @@ module FreeMessageQueue
30
30
  # forward_to: /fmq_test/test1 /fmq_test/test2
31
31
  #
32
32
  # *NOTE* the poll method is not implemented in this queue. It is a put only queue.
33
- class ForwardQueue
34
- # QueueManager refrence
35
- attr_accessor :manager
33
+ class ForwardQueue < BaseQueue
36
34
 
37
- # Bytes and size are allways 0 because this queue holds no data
38
- attr_reader :bytes, :size
39
-
40
- def initialize
41
- @bytes = @size = 0
35
+ def initialize(manager)
36
+ super(manager)
42
37
  @forwards = []
43
38
  end
44
39
 
45
- # put the data from this queue to the queues
40
+ # put the message from this queue to the queues
46
41
  # that are specified in the <em>forward-to</em> configuration option.
47
- def put(data)
42
+ def put(message)
48
43
  for forward in @forwards do
49
- @manager.put(forward, data)
44
+ @manager.put(forward, message.clone)
50
45
  end
51
46
  end
52
47
 
@@ -16,83 +16,52 @@
16
16
  # You should have received a copy of the GNU General Public License
17
17
  # along with Free Message Queue. If not, see <http://www.gnu.org/licenses/>.
18
18
  #
19
+ require File.dirname(__FILE__) + '/base'
20
+
19
21
  module FreeMessageQueue
20
- # Simple queue item class is used, because it is
21
- # considered to be faster than ostruct
22
- class QueueItem
23
- attr_accessor :next, :data, :created_at
24
-
25
- # Create queue item
26
- def initialize(data, created_at = Time.new)
27
- @data = data
28
- @created_at = created_at
29
- end
30
-
31
- # Aize of item in bytes
32
- def bytes
33
- @data.size
34
- end
35
- end
36
-
37
22
  # *DO* *NOT* *USE* *THIS* *QUEUE* *DIRECTLY* *IN* *THE* *QUEUE* *MANAGER*
38
23
  # it is not thread safe.
39
24
  # This Queue implements a FIFO based store in system memory.
40
- class LinkedQueue
41
- attr_reader :size, :bytes
42
-
43
- def initialize()
44
- @size = 0
45
- @first_item = nil
46
- @last_item = nil
47
- @bytes = 0
25
+ class LinkedQueue < BaseQueue
26
+ def initialize(manager)
27
+ super(manager)
28
+ @last_message = @first_message = nil
48
29
  end
49
30
 
50
31
  # Remove all items from the queue
51
32
  def clear
52
- if size > 0
53
- while self.poll; end
54
- end
33
+ while self.poll; end
55
34
  end
56
35
 
57
36
  # Put an item to the queue
58
- def put(data)
59
- return false if data == nil
60
-
61
- # create item
62
- qi = QueueItem.new(data)
63
-
37
+ def put(message)
38
+ return false if message == nil
39
+
64
40
  # insert at end of list
65
- if @first_item == nil
66
- @first_item = @last_item = qi
41
+ if @first_message == nil
42
+ # first and last item are same if there is no item to the queue
43
+ @first_message = @last_message = message
67
44
  else
68
- @last_item.next = qi
45
+ # append the message to the end of the queue
46
+ @last_message = @last_message.next = message
69
47
  end
70
- @last_item = qi
71
-
72
- # update queue size and memory usage
73
- @size += 1
74
- @bytes += qi.bytes
75
- true
48
+
49
+ add_message(message.bytes) # update stats
76
50
  end
77
51
 
78
- # Return an item from the queue
52
+ # Return an message from the queue or nil if the queue is empty
79
53
  def poll()
80
- if @size > 0
54
+ unless empty?
81
55
  # remove allways the first item
82
- qi = @first_item
83
-
84
- # cleanup list
85
- if @first_item == @last_item # just 1 element is in the list
86
- @first_item = @last_item = nil
87
- else
88
- @first_item = @first_item.next
89
- end
90
- qi.next = nil # remove link to next item
91
-
92
- # update queue size and memory usage
93
- @size -= 1
94
- @bytes -= qi.bytes
95
- return qi
56
+ message = @first_message
57
+
58
+ # took it off
59
+ @first_message = message.next
60
+ @last_message = nil if @first_message.nil?
61
+ message.next = nil # unlink the message
62
+ remove_message(message.bytes) # update stats
63
+
64
+ return message
96
65
  else
97
66
  return nil
98
67
  end
@@ -1,104 +1,105 @@
1
- #
2
- # Copyright (c) 2008 Vincent Landgraf
3
- #
4
- # This file is part of the Free Message Queue.
5
- #
6
- # Free Message Queue is free software: you can redistribute it and/or modify
7
- # it under the terms of the GNU General Public License as published by
8
- # the Free Software Foundation, either version 3 of the License, or
9
- # (at your option) any later version.
10
- #
11
- # Free Message Queue is distributed in the hope that it will be useful,
12
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU General Public License for more details.
15
- #
16
- # You should have received a copy of the GNU General Public License
17
- # along with Free Message Queue. If not, see <http://www.gnu.org/licenses/>.
18
- #
19
- require File.dirname(__FILE__) + '/syncronized'
20
-
21
- module FreeMessageQueue
22
- # This queue is an approach to the issue that you want to have
23
- # multiple threads at one queue at a time. Currently this is not
24
- # considered to be a stable queue. Just use it for experimental things.
25
- #
26
- # configuration sample:
27
- # queue-manager:
28
- # auto-create-queues: true
29
- # defined-queues:
30
- # test-queue-1:
31
- # path: /fmq_test/test1
32
- # max-messages: 1000000
33
- # max-size: 10kb
34
- # class: FreeMessageQueue::LoadBalancedQueue
35
- class LoadBalancedQueue
36
- # QueueManager refrence
37
- attr_accessor :manager
38
-
39
- def initialize(queue_count = 5)
40
- @queues = []
41
- queue_count.times do
42
- @queues << SyncronizedQueue.new
43
- end
44
- @poll_queue = @put_queue = 0
45
- @semaphore = Mutex.new
46
- end
47
-
48
- # delete all messages in all queues
49
- def clear
50
- @queues.each { |q| q.clear }
51
- end
52
-
53
- # size of the queue is sum of size of all load balanced queues
54
- def size
55
- size = 0
56
- @queues.each { |q| size += q.size }
57
- return size
58
- end
59
-
60
- # size of queue in bytes
61
- def bytes
62
- tmp_bytes = 0
63
- @queues.each { |q| tmp_bytes += q.bytes }
64
- return tmp_bytes
65
- end
66
-
67
- # Return one message from one of the queues
68
- def poll
69
- @queues[next_poll_index].poll
70
- end
71
-
72
- # Put an item to one of the queues
73
- def put(data)
74
- @queues[next_put_index].put(data)
75
- end
76
-
77
- private
78
-
79
- # next index acts like 'round robin'
80
- def next_poll_index
81
- @semaphore.synchronize {
82
- # continue at begin if end was reached
83
- pq = (@poll_queue + 1 == @queues.size) ? 0 : @poll_queue + 1
84
-
85
- # if current queue is emtpy use other instead if there are
86
- # some items left but try just 10 times
87
- i = 0
88
- while @queues[pq].size == 0 && self.size > 0 && i < 10
89
- pq = (@poll_queue + 1 == @queues.size) ? 0 : @poll_queue + 1
90
- i += 1
91
- end
92
-
93
- @poll_queue = pq # return index and save for next use
94
- }
95
- end
96
-
97
- # next index acts like 'round robin'
98
- def next_put_index
99
- @semaphore.synchronize {
100
- @put_queue = (@put_queue + 1 == @queues.size) ? 0 : @put_queue + 1
101
- }
102
- end
103
- end
104
- end
1
+ #
2
+ # Copyright (c) 2008 Vincent Landgraf
3
+ #
4
+ # This file is part of the Free Message Queue.
5
+ #
6
+ # Free Message Queue is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Free Message Queue is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Free Message Queue. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+ require File.dirname(__FILE__) + '/syncronized'
20
+
21
+ module FreeMessageQueue
22
+ # This queue is an approach to the issue that you want to have
23
+ # multiple threads at one queue at a time. Currently this is not
24
+ # considered to be a stable queue. Just use it for experimental things.
25
+ #
26
+ # configuration sample:
27
+ # queue-manager:
28
+ # auto-create-queues: true
29
+ # defined-queues:
30
+ # test-queue-1:
31
+ # path: /fmq_test/test1
32
+ # max-messages: 1000000
33
+ # max-size: 10kb
34
+ # class: FreeMessageQueue::LoadBalancedQueue
35
+ class LoadBalancedQueue
36
+ # QueueManager refrence
37
+ attr_accessor :manager
38
+
39
+ def initialize(manager, queue_count = 5)
40
+ @manager = manager
41
+ @queues = []
42
+ queue_count.times do
43
+ @queues << SyncronizedQueue.new(manager)
44
+ end
45
+ @poll_queue = @put_queue = 0
46
+ @semaphore = Mutex.new
47
+ end
48
+
49
+ # delete all messages in all queues
50
+ def clear
51
+ @queues.each { |q| q.clear }
52
+ end
53
+
54
+ # size of the queue is sum of size of all load balanced queues
55
+ def size
56
+ size = 0
57
+ @queues.each { |q| size += q.size }
58
+ return size
59
+ end
60
+
61
+ # size of queue in bytes
62
+ def bytes
63
+ tmp_bytes = 0
64
+ @queues.each { |q| tmp_bytes += q.bytes }
65
+ return tmp_bytes
66
+ end
67
+
68
+ # Return one message from one of the queues
69
+ def poll
70
+ @queues[next_poll_index].poll
71
+ end
72
+
73
+ # Put an item to one of the queues
74
+ def put(data)
75
+ @queues[next_put_index].put(data)
76
+ end
77
+
78
+ private
79
+
80
+ # next index acts like 'round robin'
81
+ def next_poll_index
82
+ @semaphore.synchronize {
83
+ # continue at begin if end was reached
84
+ pq = (@poll_queue + 1 == @queues.size) ? 0 : @poll_queue + 1
85
+
86
+ # if current queue is emtpy use other instead if there are
87
+ # some items left but try just 10 times
88
+ i = 0
89
+ while @queues[pq].size == 0 && self.size > 0 && i < 10
90
+ pq = (@poll_queue + 1 == @queues.size) ? 0 : @poll_queue + 1
91
+ i += 1
92
+ end
93
+
94
+ @poll_queue = pq # return index and save for next use
95
+ }
96
+ end
97
+
98
+ # next index acts like 'round robin'
99
+ def next_put_index
100
+ @semaphore.synchronize {
101
+ @put_queue = (@put_queue + 1 == @queues.size) ? 0 : @put_queue + 1
102
+ }
103
+ end
104
+ end
105
+ end
@@ -1,56 +1,55 @@
1
- #
2
- # Copyright (c) 2008 Vincent Landgraf
3
- #
4
- # This file is part of the Free Message Queue.
5
- #
6
- # Free Message Queue is free software: you can redistribute it and/or modify
7
- # it under the terms of the GNU General Public License as published by
8
- # the Free Software Foundation, either version 3 of the License, or
9
- # (at your option) any later version.
10
- #
11
- # Free Message Queue is distributed in the hope that it will be useful,
12
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU General Public License for more details.
15
- #
16
- # You should have received a copy of the GNU General Public License
17
- # along with Free Message Queue. If not, see <http://www.gnu.org/licenses/>.
18
- #
19
- require 'thread'
20
- require File.dirname(__FILE__) + '/linked'
21
-
22
- module FreeMessageQueue
23
- # The SyncronizedQueue implements a little wrapper around the
24
- # LinkedQueue to make it thread safe
25
- #
26
- # configuration sample:
27
- # queue-manager:
28
- # auto-create-queues: true
29
- # defined-queues:
30
- # test-queue-1:
31
- # path: /fmq_test/test1
32
- # max-messages: 1000000
33
- # max-size: 10kb
34
- class SyncronizedQueue < LinkedQueue
35
- attr_accessor :manager
36
-
37
- def initialize()
38
- super
39
- @semaphore = Mutex.new
40
- end
41
-
42
- # Returns one item from the queue
43
- def poll()
44
- @semaphore.synchronize {
45
- super
46
- }
47
- end
48
-
49
- # Puts one item to the queue
50
- def put(data)
51
- @semaphore.synchronize {
52
- super(data)
53
- }
54
- end
55
- end
1
+ #
2
+ # Copyright (c) 2008 Vincent Landgraf
3
+ #
4
+ # This file is part of the Free Message Queue.
5
+ #
6
+ # Free Message Queue is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Free Message Queue is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Free Message Queue. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+ require 'thread'
20
+ require File.dirname(__FILE__) + '/linked'
21
+
22
+ module FreeMessageQueue
23
+ # The SyncronizedQueue implements a little wrapper around the
24
+ # LinkedQueue to make it thread safe
25
+ #
26
+ # configuration sample:
27
+ # queue-manager:
28
+ # auto-create-queues: true
29
+ # defined-queues:
30
+ # test-queue-1:
31
+ # path: /fmq_test/test1
32
+ # max-messages: 1000000
33
+ # max-size: 10kb
34
+ class SyncronizedQueue < LinkedQueue
35
+
36
+ def initialize(manager)
37
+ super(manager)
38
+ @semaphore = Mutex.new
39
+ end
40
+
41
+ # Returns one item from the queue
42
+ def poll()
43
+ @semaphore.synchronize {
44
+ super
45
+ }
46
+ end
47
+
48
+ # Puts one item to the queue
49
+ def put(data)
50
+ @semaphore.synchronize {
51
+ super(data)
52
+ }
53
+ end
54
+ end
56
55
  end
data/lib/fmq/version.rb CHANGED
@@ -19,8 +19,8 @@
19
19
  module FreeMessageQueue
20
20
  module VERSION #:nodoc:
21
21
  MAJOR = 0
22
- MINOR = 1
23
- TINY = 1
22
+ MINOR = 2
23
+ TINY = 0
24
24
 
25
25
  STRING = [MAJOR, MINOR, TINY].join('.')
26
26
  end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ # This is the default test to the message interface
4
+ class TestMessage < Test::Unit::TestCase
5
+ def test_initialize
6
+ msg = FreeMessageQueue::Message.new("....", "text/xml")
7
+ msg.option['application'] = "fast_app"
8
+ msg.option['expires'] = msg.created_at + (5 * 60) # 5 min after creation
9
+
10
+ assert_equal 4, msg.bytes
11
+ assert_equal 2, msg.option.size
12
+ assert_equal "text/xml", msg.content_type
13
+ assert_equal "fast_app", msg.option["application"]
14
+ end
15
+
16
+ def test_linking_of_messages
17
+ msg_0 = FreeMessageQueue::Message.new("MyMac")
18
+ msg_1 = FreeMessageQueue::Message.new("MyDesk")
19
+ msg_2 = FreeMessageQueue::Message.new("MyRuby")
20
+
21
+ msg_0.next = msg_1
22
+ msg_1.next = msg_2
23
+
24
+ assert_equal msg_2, msg_0.next.next
25
+ end
26
+ end
27
+
28
+ class BaseQueue < Test::Unit::TestCase
29
+ def test_initialize
30
+ manager = "pseudo manager"
31
+ queue = FreeMessageQueue::BaseQueue.new(manager)
32
+ assert_equal 0, queue.size
33
+ assert_equal 0, queue.bytes
34
+ assert_equal manager, queue.manager
35
+ end
36
+ end