fmq 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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