couchproxy 0.1.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.
Files changed (39) hide show
  1. data/LICENSE +19 -0
  2. data/README +36 -0
  3. data/Rakefile +42 -0
  4. data/bin/couchproxy +88 -0
  5. data/conf/couchproxy.yml +21 -0
  6. data/lib/couchproxy/cluster.rb +43 -0
  7. data/lib/couchproxy/collator.rb +60 -0
  8. data/lib/couchproxy/deferrable_body.rb +15 -0
  9. data/lib/couchproxy/node.rb +25 -0
  10. data/lib/couchproxy/partition.rb +15 -0
  11. data/lib/couchproxy/rack/active_tasks.rb +9 -0
  12. data/lib/couchproxy/rack/all_databases.rb +23 -0
  13. data/lib/couchproxy/rack/all_docs.rb +9 -0
  14. data/lib/couchproxy/rack/base.rb +197 -0
  15. data/lib/couchproxy/rack/bulk_docs.rb +68 -0
  16. data/lib/couchproxy/rack/changes.rb +9 -0
  17. data/lib/couchproxy/rack/compact.rb +16 -0
  18. data/lib/couchproxy/rack/config.rb +16 -0
  19. data/lib/couchproxy/rack/database.rb +83 -0
  20. data/lib/couchproxy/rack/design_doc.rb +227 -0
  21. data/lib/couchproxy/rack/doc.rb +15 -0
  22. data/lib/couchproxy/rack/ensure_full_commit.rb +16 -0
  23. data/lib/couchproxy/rack/not_found.rb +13 -0
  24. data/lib/couchproxy/rack/replicate.rb +9 -0
  25. data/lib/couchproxy/rack/revs_limit.rb +18 -0
  26. data/lib/couchproxy/rack/root.rb +10 -0
  27. data/lib/couchproxy/rack/stats.rb +53 -0
  28. data/lib/couchproxy/rack/temp_view.rb +9 -0
  29. data/lib/couchproxy/rack/update.rb +11 -0
  30. data/lib/couchproxy/rack/users.rb +9 -0
  31. data/lib/couchproxy/rack/uuids.rb +9 -0
  32. data/lib/couchproxy/rack/view_cleanup.rb +16 -0
  33. data/lib/couchproxy/reducer.rb +57 -0
  34. data/lib/couchproxy/request.rb +50 -0
  35. data/lib/couchproxy/router.rb +62 -0
  36. data/lib/couchproxy.rb +48 -0
  37. data/lib/couchproxy.ru +22 -0
  38. data/test/collator_test.rb +100 -0
  39. metadata +164 -0
@@ -0,0 +1,62 @@
1
+ # encoding: UTF-8
2
+
3
+ module CouchProxy
4
+ class Router
5
+ DB_NAME = '[a-z]([a-z0-9_$()+-]|%2[489bBfF])*'.freeze
6
+ ROOT = ''.freeze
7
+ UUIDS = '_uuids'.freeze
8
+ USERS = '_users'.freeze
9
+ STATS = '_stats'.freeze
10
+ REPLICATE = '_replicate'.freeze
11
+ ALL_DBS = '_all_dbs'.freeze
12
+ ACTIVE_TASKS = '_active_tasks'.freeze
13
+ CONFIG = /^(_config|_config\/.*)$/
14
+ BULK_DOCS = /^#{DB_NAME}\/_bulk_docs$/
15
+ ALL_DOCS = /^#{DB_NAME}\/_all_docs$/
16
+ DESIGN_DOC = /^#{DB_NAME}\/_design\/.+$/
17
+ COMPACT = /^#{DB_NAME}\/(_compact|_compact\/.*)$/
18
+ VIEW_CLEANUP = /^#{DB_NAME}\/_view_cleanup$/
19
+ TEMP_VIEW = /^#{DB_NAME}\/_temp_view$/
20
+ UPDATE = /^#{DB_NAME}\/_update$/
21
+ REVS_LIMIT = /^#{DB_NAME}\/_revs_limit$/
22
+ CHANGES = /^#{DB_NAME}\/_changes$/
23
+ FULL_COMMIT = /^#{DB_NAME}\/_ensure_full_commit$/
24
+ DATABASE = /^#{DB_NAME}$/
25
+ DOC = /^#{DB_NAME}\/.+$/
26
+
27
+ def initialize(cluster)
28
+ @cluster = cluster
29
+ end
30
+
31
+ def call(env)
32
+ request = ::Rack::Request.new(env)
33
+ app = case env['REQUEST_PATH'][1..-1].chomp('/')
34
+ when ROOT then :root
35
+ when UUIDS then :uuids
36
+ when CONFIG then :config
37
+ when USERS then :users
38
+ when STATS then :stats
39
+ when REPLICATE then :replicate
40
+ when ALL_DBS then :all_databases
41
+ when ACTIVE_TASKS then :active_tasks
42
+ when BULK_DOCS then :bulk_docs
43
+ when ALL_DOCS then :all_docs
44
+ when DESIGN_DOC then :design_doc
45
+ when COMPACT then :compact
46
+ when VIEW_CLEANUP then :view_cleanup
47
+ when TEMP_VIEW then :temp_view
48
+ when UPDATE then :update
49
+ when REVS_LIMIT then :revs_limit
50
+ when CHANGES then :changes
51
+ when FULL_COMMIT then :ensure_full_commit
52
+ when DATABASE then :database
53
+ when DOC then :doc
54
+ else :not_found
55
+ end
56
+ name = app.to_s.split('_').map {|n| n.capitalize }.join
57
+ app = CouchProxy::Rack.const_get(name).new(request, @cluster)
58
+ app.send(request.request_method.downcase)
59
+ throw :async
60
+ end
61
+ end
62
+ end
data/lib/couchproxy.rb ADDED
@@ -0,0 +1,48 @@
1
+ # encoding: UTF-8
2
+
3
+ $:.unshift File.dirname(__FILE__) unless
4
+ $:.include?(File.dirname(__FILE__))
5
+
6
+ %w[
7
+ em-http
8
+ json
9
+ json/stream
10
+ thin
11
+ time
12
+ uri
13
+ yaml
14
+ zlib
15
+
16
+ couchproxy/collator
17
+ couchproxy/cluster
18
+ couchproxy/node
19
+ couchproxy/partition
20
+ couchproxy/deferrable_body
21
+ couchproxy/reducer
22
+ couchproxy/request
23
+ couchproxy/router
24
+
25
+ couchproxy/rack/base
26
+ couchproxy/rack/all_databases
27
+ couchproxy/rack/bulk_docs
28
+ couchproxy/rack/changes
29
+ couchproxy/rack/compact
30
+ couchproxy/rack/config
31
+ couchproxy/rack/database
32
+ couchproxy/rack/design_doc
33
+ couchproxy/rack/doc
34
+ couchproxy/rack/ensure_full_commit
35
+ couchproxy/rack/not_found
36
+ couchproxy/rack/replicate
37
+ couchproxy/rack/revs_limit
38
+ couchproxy/rack/root
39
+ couchproxy/rack/stats
40
+ couchproxy/rack/update
41
+ couchproxy/rack/users
42
+ couchproxy/rack/uuids
43
+ couchproxy/rack/view_cleanup
44
+ ].each {|f| require f }
45
+
46
+ module CouchProxy
47
+ VERSION = '0.1.0'
48
+ end
data/lib/couchproxy.ru ADDED
@@ -0,0 +1,22 @@
1
+ $:.unshift File.dirname(__FILE__) unless
2
+ $:.include?(File.dirname(__FILE__))
3
+
4
+ require 'couchproxy'
5
+
6
+ def cluster
7
+ yaml = ENV['COUCH_PROXY_CONFIG'] || ''
8
+ unless File.exist?(yaml)
9
+ raise ArgumentError.new('COUCH_PROXY_CONFIG must point to a couchproxy.yml file')
10
+ end
11
+ config = YAML.load_file(yaml)
12
+ raise ArgumentError.new('must define node list') unless config['nodes']
13
+ nodes = config['nodes'].map {|n| CouchProxy::Node.new(n['host'], n['partitions']) }
14
+ reducers = config['reducers'] || 4
15
+ couchjs = config['couchjs'] or raise ArgumentError.new('must define couchjs')
16
+ raise ArgumentError.new("#{couchjs} must be executable") unless File.executable?(couchjs)
17
+ mainjs = File.expand_path('../../share/couchdb/server/main.js', couchjs)
18
+ raise ArgumentError.new("could not find #{mainjs}") unless File.exist?(mainjs)
19
+ CouchProxy::Cluster.new(nodes, couchjs, reducers)
20
+ end
21
+
22
+ run CouchProxy::Router.new(cluster)
@@ -0,0 +1,100 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'couchproxy'
4
+ require 'test/unit'
5
+
6
+ # Test that we properly sort JSON keys according to
7
+ # http://wiki.apache.org/couchdb/View_collation.
8
+ class CollatorTest < Test::Unit::TestCase
9
+ def setup
10
+ @collator = CouchProxy::Collator.new
11
+ end
12
+
13
+ def test_keyword
14
+ assert_equal(0, @collator.compare(nil, nil))
15
+ assert_equal(0, @collator.compare(true, true))
16
+ assert_equal(0, @collator.compare(false, false))
17
+
18
+ assert_equal(-1, @collator.compare(nil, false))
19
+ assert_equal(1, @collator.compare(false, nil))
20
+
21
+ assert_equal(-1, @collator.compare(nil, true))
22
+ assert_equal(1, @collator.compare(true, nil))
23
+
24
+ assert_equal(-1, @collator.compare(false, true))
25
+ assert_equal(1, @collator.compare(true, false))
26
+ end
27
+
28
+ def test_number
29
+ assert_equal(0, @collator.compare(0, 0))
30
+ assert_equal(0, @collator.compare(0, 0.0))
31
+ assert_equal(0, @collator.compare(1, 1.0))
32
+ assert_equal(-1, @collator.compare(0, 1.0))
33
+ assert_equal(1, @collator.compare(1.0, 0))
34
+ end
35
+
36
+ def test_string
37
+ assert_equal(0, @collator.compare('', ''))
38
+ assert_equal(0, @collator.compare('a', 'a'))
39
+ assert_equal(-1, @collator.compare('a', 'aa'))
40
+ assert_equal(-1, @collator.compare('a', 'b'))
41
+ assert_equal(1, @collator.compare('b', 'a'))
42
+ end
43
+
44
+ def test_type
45
+ assert_equal(-1, @collator.compare(nil, 0))
46
+ assert_equal(-1, @collator.compare(nil, ''))
47
+ assert_equal(-1, @collator.compare(nil, []))
48
+ assert_equal(-1, @collator.compare(nil, {}))
49
+
50
+ assert_equal(-1, @collator.compare(true, 0))
51
+ assert_equal(-1, @collator.compare(true, ''))
52
+ assert_equal(-1, @collator.compare(true, []))
53
+ assert_equal(-1, @collator.compare(true, {}))
54
+
55
+ assert_equal(-1, @collator.compare(false, 0))
56
+ assert_equal(-1, @collator.compare(false, ''))
57
+ assert_equal(-1, @collator.compare(false, []))
58
+ assert_equal(-1, @collator.compare(false, {}))
59
+
60
+ assert_equal(-1, @collator.compare(0, ''))
61
+ assert_equal(-1, @collator.compare(0, []))
62
+ assert_equal(-1, @collator.compare(0, {}))
63
+
64
+ assert_equal(-1, @collator.compare('', []))
65
+ assert_equal(-1, @collator.compare('', {}))
66
+
67
+ assert_equal(-1, @collator.compare([], {}))
68
+ end
69
+
70
+ def test_array
71
+ assert_equal(0, @collator.compare([], []))
72
+ assert_equal(0, @collator.compare([0], [0]))
73
+ assert_equal(0, @collator.compare([0], [0.0]))
74
+
75
+ assert_equal(-1, @collator.compare([], [0]))
76
+ assert_equal(-1, @collator.compare([0], [0, 1]))
77
+ assert_equal(1, @collator.compare([0], []))
78
+ assert_equal(1, @collator.compare([0, 1], [0]))
79
+
80
+ assert_equal(1, @collator.compare([0], [-1, 0]))
81
+ assert_equal(-1, @collator.compare([-1, 0], [0]))
82
+
83
+ assert_equal(-1, @collator.compare([nil], [false]))
84
+ assert_equal(-1, @collator.compare([nil], [nil, false]))
85
+
86
+ assert_equal(0, @collator.compare([[]], [[]]))
87
+ assert_equal(-1, @collator.compare([[0]], [[1]]))
88
+ assert_equal(-1, @collator.compare([0], [[]]))
89
+ end
90
+
91
+ def test_hash
92
+ assert_equal(0, @collator.compare({}, {}))
93
+ assert_equal(0, @collator.compare({nil => nil}, {nil => nil}))
94
+ assert_equal(-1, @collator.compare({nil => nil}, {nil => true}))
95
+ assert_equal(1, @collator.compare({nil => true}, {nil => nil}))
96
+ assert_equal(-1, @collator.compare({'a' => 1}, {'a' => 2}))
97
+ assert_equal(-1, @collator.compare({'b' => 2}, {'b' => 2, 'a' => 1}))
98
+ assert_equal(-1, @collator.compare({'b' => 2, 'a' => 1}, {'b' => 2, 'c' => 2}))
99
+ end
100
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: couchproxy
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - David Graham
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-09-06 00:00:00 -06:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: em-http-request
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ - 2
31
+ version: "0.2"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: json
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 1
44
+ - 4
45
+ version: "1.4"
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: json-stream
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 0
58
+ - 1
59
+ version: "0.1"
60
+ type: :runtime
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: thin
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 1
72
+ - 2
73
+ version: "1.2"
74
+ type: :runtime
75
+ version_requirements: *id004
76
+ description: |-
77
+ CouchProxy is a simple proxy server that distributes reads and writes to a
78
+ cluster of Apache CouchDB servers so they appear to be a single huge database.
79
+ Documents are stored and retrieved from a particular CouchDB instance, using
80
+ consistent hashing of the document id. Map/reduce views are processed
81
+ concurrently on each CouchDB instance and merged together by the proxy before
82
+ returning the results to the client.
83
+ email: david.malcom.graham@gmail.com
84
+ executables:
85
+ - couchproxy
86
+ extensions: []
87
+
88
+ extra_rdoc_files: []
89
+
90
+ files:
91
+ - LICENSE
92
+ - Rakefile
93
+ - README
94
+ - bin/couchproxy
95
+ - lib/couchproxy/cluster.rb
96
+ - lib/couchproxy/collator.rb
97
+ - lib/couchproxy/deferrable_body.rb
98
+ - lib/couchproxy/node.rb
99
+ - lib/couchproxy/partition.rb
100
+ - lib/couchproxy/rack/active_tasks.rb
101
+ - lib/couchproxy/rack/all_databases.rb
102
+ - lib/couchproxy/rack/all_docs.rb
103
+ - lib/couchproxy/rack/base.rb
104
+ - lib/couchproxy/rack/bulk_docs.rb
105
+ - lib/couchproxy/rack/changes.rb
106
+ - lib/couchproxy/rack/compact.rb
107
+ - lib/couchproxy/rack/config.rb
108
+ - lib/couchproxy/rack/database.rb
109
+ - lib/couchproxy/rack/design_doc.rb
110
+ - lib/couchproxy/rack/doc.rb
111
+ - lib/couchproxy/rack/ensure_full_commit.rb
112
+ - lib/couchproxy/rack/not_found.rb
113
+ - lib/couchproxy/rack/replicate.rb
114
+ - lib/couchproxy/rack/revs_limit.rb
115
+ - lib/couchproxy/rack/root.rb
116
+ - lib/couchproxy/rack/stats.rb
117
+ - lib/couchproxy/rack/temp_view.rb
118
+ - lib/couchproxy/rack/update.rb
119
+ - lib/couchproxy/rack/users.rb
120
+ - lib/couchproxy/rack/uuids.rb
121
+ - lib/couchproxy/rack/view_cleanup.rb
122
+ - lib/couchproxy/reducer.rb
123
+ - lib/couchproxy/request.rb
124
+ - lib/couchproxy/router.rb
125
+ - lib/couchproxy.rb
126
+ - lib/couchproxy.ru
127
+ - conf/couchproxy.yml
128
+ - test/collator_test.rb
129
+ has_rdoc: true
130
+ homepage: http://github.com/dgraham/couchproxy
131
+ licenses: []
132
+
133
+ post_install_message:
134
+ rdoc_options: []
135
+
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ segments:
144
+ - 1
145
+ - 9
146
+ - 1
147
+ version: 1.9.1
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ none: false
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ segments:
154
+ - 0
155
+ version: "0"
156
+ requirements: []
157
+
158
+ rubyforge_project:
159
+ rubygems_version: 1.3.7
160
+ signing_key:
161
+ specification_version: 3
162
+ summary: A proxy server for Apache CouchDB clusters.
163
+ test_files:
164
+ - test/collator_test.rb