riak-client 1.0.0.beta → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -4
- data/Gemfile +12 -17
- data/Guardfile +1 -1
- data/LICENSE +16 -0
- data/README.markdown +178 -0
- data/RELEASE_NOTES.md +99 -0
- data/Rakefile +25 -1
- data/erl_src/riak_kv_test014_backend.beam +0 -0
- data/erl_src/riak_kv_test014_backend.erl +189 -0
- data/erl_src/riak_kv_test_backend.beam +0 -0
- data/erl_src/riak_kv_test_backend.erl +37 -19
- data/lib/riak/client.rb +322 -272
- data/lib/riak/client/beefcake_protobuffs_backend.rb +6 -10
- data/lib/riak/client/decaying.rb +28 -0
- data/lib/riak/client/excon_backend.rb +27 -11
- data/lib/riak/client/http_backend.rb +71 -2
- data/lib/riak/client/http_backend/configuration.rb +17 -3
- data/lib/riak/client/http_backend/transport_methods.rb +3 -3
- data/lib/riak/client/net_http_backend.rb +18 -14
- data/lib/riak/client/node.rb +111 -0
- data/lib/riak/client/pool.rb +180 -0
- data/lib/riak/client/protobuffs_backend.rb +15 -5
- data/lib/riak/client/search.rb +9 -3
- data/lib/riak/link.rb +5 -7
- data/lib/riak/locale/en.yml +1 -0
- data/lib/riak/node/configuration.rb +1 -0
- data/lib/riak/node/defaults.rb +19 -6
- data/lib/riak/node/generation.rb +9 -2
- data/lib/riak/node/log.rb +2 -2
- data/lib/riak/node/version.rb +22 -16
- data/lib/riak/robject.rb +19 -3
- data/lib/riak/serializers.rb +1 -1
- data/lib/riak/test_server.rb +10 -2
- data/lib/riak/version.rb +1 -1
- data/riak-client.gemspec +3 -3
- data/spec/failover/failover.rb +59 -0
- data/spec/integration/riak/http_backends_spec.rb +2 -2
- data/spec/integration/riak/node_spec.rb +16 -24
- data/spec/integration/riak/protobuffs_backends_spec.rb +1 -1
- data/spec/integration/riak/test_server_spec.rb +4 -3
- data/spec/integration/riak/threading_spec.rb +193 -0
- data/spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb +23 -0
- data/spec/riak/beefcake_protobuffs_backend_spec.rb +4 -2
- data/spec/riak/bucket_spec.rb +2 -1
- data/spec/riak/client_spec.rb +80 -181
- data/spec/riak/excon_backend_spec.rb +3 -2
- data/spec/riak/http_backend/configuration_spec.rb +37 -5
- data/spec/riak/http_backend/object_methods_spec.rb +1 -1
- data/spec/riak/http_backend/transport_methods_spec.rb +2 -2
- data/spec/riak/http_backend_spec.rb +53 -3
- data/spec/riak/map_reduce_spec.rb +1 -1
- data/spec/riak/net_http_backend_spec.rb +1 -2
- data/spec/riak/node_spec.rb +173 -0
- data/spec/riak/pool_spec.rb +306 -0
- data/spec/riak/robject_spec.rb +8 -4
- data/spec/riak/search_spec.rb +66 -15
- data/spec/riak/serializers_spec.rb +12 -1
- data/spec/spec_helper.rb +9 -1
- data/spec/support/http_backend_implementation_examples.rb +6 -2
- data/spec/support/sometimes.rb +46 -0
- data/spec/support/test_server.rb +50 -19
- data/spec/support/unified_backend_examples.rb +11 -10
- data/spec/support/version_filter.rb +14 -0
- metadata +40 -29
- data/lib/active_support/cache/riak_store.rb +0 -2
- data/lib/riak/cache_store.rb +0 -84
- data/lib/riak/client/pump.rb +0 -30
- data/lib/riak/util/fiber1.8.rb +0 -48
- data/spec/integration/riak/cache_store_spec.rb +0 -129
data/.gitignore
CHANGED
@@ -14,11 +14,12 @@ tmtags
|
|
14
14
|
*.swp
|
15
15
|
|
16
16
|
## PROJECT::GENERAL
|
17
|
-
coverage
|
18
|
-
rdoc
|
19
|
-
pkg
|
17
|
+
coverage
|
18
|
+
rdoc
|
19
|
+
pkg
|
20
20
|
|
21
21
|
## PROJECT::SPECIFIC
|
22
|
+
_notes
|
22
23
|
doc
|
23
24
|
.yardoc
|
24
25
|
.bundle
|
@@ -28,5 +29,7 @@ Gemfile.lock
|
|
28
29
|
*.rbc
|
29
30
|
.rvmrc
|
30
31
|
|
31
|
-
.ripplenode
|
32
32
|
.riaktest
|
33
|
+
**/.riaktest
|
34
|
+
vendor/erlang
|
35
|
+
vendor/riak
|
data/Gemfile
CHANGED
@@ -2,10 +2,13 @@ source :rubygems
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
gem 'bundler'
|
5
|
-
gem 'guard-rspec'
|
6
|
-
gem 'rb-fsevent'
|
7
|
-
gem 'growl'
|
8
5
|
|
6
|
+
group :guard do
|
7
|
+
gem 'guard-rspec'
|
8
|
+
gem 'rb-fsevent'
|
9
|
+
gem 'growl'
|
10
|
+
end
|
11
|
+
|
9
12
|
platforms :mri do
|
10
13
|
gem 'yajl-ruby'
|
11
14
|
end
|
@@ -14,18 +17,10 @@ platforms :jruby do
|
|
14
17
|
gem 'jruby-openssl'
|
15
18
|
end
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
else
|
21
|
-
gem 'activesupport', '~> 3.0.10'
|
22
|
-
end
|
23
|
-
end
|
20
|
+
# platforms :mri_18, :jruby do
|
21
|
+
# gem 'ruby-debug'
|
22
|
+
# end
|
24
23
|
|
25
|
-
platforms :
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
platforms :mri_19 do
|
30
|
-
gem 'ruby-debug19'
|
31
|
-
end
|
24
|
+
# platforms :mri_19 do
|
25
|
+
# gem 'ruby-debug19'
|
26
|
+
# end
|
data/Guardfile
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Copyright 2010-2011 Sean Cribbs and Basho Technologies, Inc.
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
14
|
+
|
15
|
+
All of the files in this project are under the project-wide license
|
16
|
+
unless they are otherwise marked.
|
data/README.markdown
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
# Riak Ruby Client (riak-client) [![Build Status](https://secure.travis-ci.org/basho/riak-ruby-client.png)](http://travis-ci.org/basho/riak-ruby-client)
|
2
|
+
|
3
|
+
`riak-client` is a rich Ruby client/toolkit for Riak, Basho's
|
4
|
+
distributed database that contains a basic wrapper around typical
|
5
|
+
operations, including bucket manipulation, object CRUD, link-walking,
|
6
|
+
and map-reduce.
|
7
|
+
|
8
|
+
## Dependencies
|
9
|
+
|
10
|
+
`riak-client` requires i18n, builder, beefcake, and multi_json. For
|
11
|
+
higher performance on HTTP requests, install the 'excon' gem. The
|
12
|
+
cache store implementation requires ActiveSupport 3 or later.
|
13
|
+
|
14
|
+
Development dependencies are handled with bundler. Install bundler
|
15
|
+
(`gem install bundler`) and run this command in each sub-project to
|
16
|
+
get started:
|
17
|
+
|
18
|
+
``` bash
|
19
|
+
$ bundle install
|
20
|
+
```
|
21
|
+
|
22
|
+
Run the RSpec suite using `bundle exec`:
|
23
|
+
|
24
|
+
``` bash
|
25
|
+
$ bundle exec rake
|
26
|
+
```
|
27
|
+
|
28
|
+
## Basic Example
|
29
|
+
|
30
|
+
``` ruby
|
31
|
+
require 'riak'
|
32
|
+
|
33
|
+
# Create a client interface
|
34
|
+
client = Riak::Client.new
|
35
|
+
|
36
|
+
# Create a client interface that uses Excon
|
37
|
+
client = Riak::Client.new(:http_backend => :Excon)
|
38
|
+
|
39
|
+
# Create a client that uses Protocol Buffers
|
40
|
+
client = Riak::Client.new(:protocol => "pbc")
|
41
|
+
|
42
|
+
# Automatically balance between multiple nodes
|
43
|
+
client = Riak::Client.new(:nodes => [
|
44
|
+
{:host => '10.0.0.1'},
|
45
|
+
{:host => '10.0.0.2', :pb_port => 1234},
|
46
|
+
{:host => '10.0.0.3', :http_port => 5678}
|
47
|
+
])
|
48
|
+
|
49
|
+
# Retrieve a bucket
|
50
|
+
bucket = client.bucket("doc") # a Riak::Bucket
|
51
|
+
|
52
|
+
# Get an object from the bucket
|
53
|
+
object = bucket.get_or_new("index.html") # a Riak::RObject
|
54
|
+
|
55
|
+
# Change the object's data and save
|
56
|
+
object.data = "<html><body>Hello, world!</body></html>"
|
57
|
+
object.content_type = "text/html"
|
58
|
+
object.store
|
59
|
+
|
60
|
+
# Reload an object you already have
|
61
|
+
object.reload # Works if you have the key and vclock, using conditional GET
|
62
|
+
object.reload :force => true # Reloads whether you have the vclock or not
|
63
|
+
|
64
|
+
# Access more like a hash, client[bucket][key]
|
65
|
+
client['doc']['index.html'] # the Riak::RObject
|
66
|
+
|
67
|
+
# Create a new object
|
68
|
+
new_one = Riak::RObject.new(bucket, "application.js")
|
69
|
+
new_one.content_type = "application/javascript" # You must set the content type.
|
70
|
+
new_one.data = "alert('Hello, World!')"
|
71
|
+
new_one.store
|
72
|
+
```
|
73
|
+
|
74
|
+
## Map-Reduce Example
|
75
|
+
|
76
|
+
``` ruby
|
77
|
+
# Assuming you've already instantiated a client, get the album titles for The Beatles
|
78
|
+
results = Riak::MapReduce.new(client).
|
79
|
+
add("artists","Beatles").
|
80
|
+
link(:bucket => "albums").
|
81
|
+
map("function(v){ return [JSON.parse(v.values[0].data).title]; }", :keep => true).run
|
82
|
+
|
83
|
+
p results # => ["Please Please Me", "With The Beatles", "A Hard Day's Night",
|
84
|
+
# "Beatles For Sale", "Help!", "Rubber Soul",
|
85
|
+
# "Revolver", "Sgt. Pepper's Lonely Hearts Club Band", "Magical Mystery Tour",
|
86
|
+
# "The Beatles", "Yellow Submarine", "Abbey Road", "Let It Be"]
|
87
|
+
```
|
88
|
+
|
89
|
+
|
90
|
+
## Riak Search Examples
|
91
|
+
|
92
|
+
For more information about Riak Search, see [the Basho wiki](http://wiki.basho.com/Riak-Search.html).
|
93
|
+
|
94
|
+
``` ruby
|
95
|
+
# Create a client, specifying the Solr-compatible endpoint
|
96
|
+
# When connecting to Riak 0.14 and later, the Solr endpoint configuration option is not necessary.
|
97
|
+
client = Riak::Client.new :solr => "/solr"
|
98
|
+
|
99
|
+
# Search the default index for documents
|
100
|
+
result = client.search("title:Yesterday") # Returns a vivified JSON object
|
101
|
+
# containing 'responseHeaders' and 'response' keys
|
102
|
+
result['response']['numFound'] # total number of results
|
103
|
+
result['response']['start'] # offset into the total result set
|
104
|
+
result['response']['docs'] # the list of indexed documents
|
105
|
+
|
106
|
+
# Search the 'users' index for documents
|
107
|
+
client.search("users", "name:Sean")
|
108
|
+
|
109
|
+
# Add a document to an index
|
110
|
+
client.index("users", {:id => "sean@basho.com", :name => "Sean Cribbs"}) # adds to the 'users' index
|
111
|
+
|
112
|
+
client.index({:id => "index.html", :content => "Hello, world!"}) # adds to the default index
|
113
|
+
|
114
|
+
client.index({:id => 1, :name => "one"}, {:id => 2, :name => "two"}) # adds multiple docs
|
115
|
+
|
116
|
+
# Remove document(s) from an index
|
117
|
+
client.remove({:id => 1}) # removes the document with ID 1
|
118
|
+
client.remove({:query => "archived"}) # removes all documents matching query
|
119
|
+
client.remove({:id => 1}, {:id => 5}) # removes multiple docs
|
120
|
+
|
121
|
+
client.remove("users", {:id => "sean@basho.com"}) # removes from the 'users' index
|
122
|
+
|
123
|
+
# Seed MapReduce with search results
|
124
|
+
Riak::MapReduce.new(client).
|
125
|
+
search("users","email:basho").
|
126
|
+
map("Riak.mapValuesJson", :keep => true).
|
127
|
+
run
|
128
|
+
|
129
|
+
# Detect whether a bucket has auto-indexing
|
130
|
+
client['users'].is_indexed?
|
131
|
+
|
132
|
+
# Enable auto-indexing on a bucket
|
133
|
+
client['users'].enable_index!
|
134
|
+
|
135
|
+
# Disable auto-indexing on a bucket
|
136
|
+
client['users'].disable_index!
|
137
|
+
```
|
138
|
+
|
139
|
+
## How to Contribute
|
140
|
+
|
141
|
+
* Fork the project on [Github](http://github.com/basho/riak-ruby-client). If you have already forked, use `git pull --rebase` to reapply your changes on top of the mainline. Example:
|
142
|
+
|
143
|
+
``` bash
|
144
|
+
$ git checkout master
|
145
|
+
$ git pull --rebase basho master
|
146
|
+
```
|
147
|
+
* Create a topic branch. If you've already created a topic branch, rebase it on top of changes from the mainline "master" branch. Examples:
|
148
|
+
* New branch:
|
149
|
+
|
150
|
+
``` bash
|
151
|
+
$ git checkout -b topic
|
152
|
+
```
|
153
|
+
* Existing branch:
|
154
|
+
|
155
|
+
``` bash
|
156
|
+
$ git rebase master
|
157
|
+
```
|
158
|
+
* Write an RSpec example or set of examples that demonstrate the necessity and validity of your changes. **Patches without specs will most often be ignored. Just do it, you'll thank me later.** Documentation patches need no specs, of course.
|
159
|
+
* Make your feature addition or bug fix. Make your specs and stories pass (green).
|
160
|
+
* Run the suite using multiruby or rvm to ensure cross-version compatibility.
|
161
|
+
* Cleanup any trailing whitespace in your code (try @whitespace-mode@ in Emacs, or "Remove Trailing Spaces in Document" in the "Text" bundle in Textmate). You can use the `clean_whitespace` Rake task if you like.
|
162
|
+
* Commit, do not mess with Rakefile. If related to an existing issue in the [tracker](http://github.com/basho/ruby-riak-client/issues), include "Closes #X" in the commit message (where X is the issue number).
|
163
|
+
* Send a pull request to the Basho repository.
|
164
|
+
|
165
|
+
## License & Copyright
|
166
|
+
|
167
|
+
Copyright ©2010-2012 Sean Cribbs and Basho Technologies, Inc.
|
168
|
+
|
169
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
170
|
+
|
171
|
+
[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
172
|
+
|
173
|
+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
174
|
+
|
175
|
+
## Auxillary Licenses
|
176
|
+
|
177
|
+
The included photo (spec/fixtures/cat.jpg) is Copyright ©2009 [Sean Cribbs](http://seancribbs.com/), and is licensed under the [Creative Commons Attribution Non-Commercial 3.0](http://creativecommons.org/licenses/by-nc/3.0) license.
|
178
|
+
!["Creative Commons"](http://i.creativecommons.org/l/by-nc/3.0/88x31.png)
|
data/RELEASE_NOTES.md
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# Riak Ruby Client Release Notes
|
2
|
+
|
3
|
+
## 1.0.0 Feature Release - 2012-02-03
|
4
|
+
|
5
|
+
Release 1.0.0 is a major feature release and is the first where
|
6
|
+
`riak-client`, `ripple`, and `riak-sessions` will be released
|
7
|
+
independently (see below). Because there too many individual changes
|
8
|
+
to recount, this entry will cover the major features and bugfixes
|
9
|
+
present in the release.
|
10
|
+
|
11
|
+
### Riak 1.0/1.1 Compatibility
|
12
|
+
|
13
|
+
`riak-client` is fully compatible with Riak 1.0.x and
|
14
|
+
(yet-to-be-released) 1.1.x, including supporting secondary indexes,
|
15
|
+
integrated search, and cluster membership commands.
|
16
|
+
|
17
|
+
### Multi-node Connections and Retries
|
18
|
+
|
19
|
+
`Riak::Client` can now connect to multiple Riak nodes at once. This
|
20
|
+
greatly improves throughput and allows the client to recover from
|
21
|
+
intermittent connection errors while continuing normal operation. To
|
22
|
+
enable this, all uses of the Pump/Fiber logic were removed in favor of
|
23
|
+
connection pools from which any new request can draw an existing or
|
24
|
+
create a new connection. Which node is selected for any new connection
|
25
|
+
is based on a quickly-decaying EWMA of its success rate on recent
|
26
|
+
requests. A huge thanks to [Kyle Kingsbury](https://github.com/aphyr)
|
27
|
+
who did most of the work on this!
|
28
|
+
|
29
|
+
### Improved TestServer and Node Generation
|
30
|
+
|
31
|
+
The `Riak::TestServer` class has been generalized such that you can
|
32
|
+
generate regular nodes and even clusters that store data on disk. This
|
33
|
+
is especially useful if you want separate nodes or clusters for each
|
34
|
+
project that uses Riak, and to keep them separate from your base
|
35
|
+
install. `TestServer` also now launches the node in a separate process
|
36
|
+
(not a child process) so you can keep it running between test
|
37
|
+
suites. Clearing the in-memory data is performed by connecting to the
|
38
|
+
console via the exposed Unix pipes, rather than over stdio.
|
39
|
+
|
40
|
+
### Conflict Resolution
|
41
|
+
|
42
|
+
An important part of dealing with eventual consistency is the ability
|
43
|
+
to handle when conflicts (also called siblings) are created. Now you
|
44
|
+
can resolve them automatically by registering blocks (callbacks) using
|
45
|
+
`Riak::RObject.on_conflict`. The block will be called when fetching a
|
46
|
+
key in conflict and receives a `RObject` that has siblings. To resolve
|
47
|
+
the conflict, it simply returns the resolved object, or nil if it
|
48
|
+
didn't handle the conflict. A huge thanks to
|
49
|
+
[Myron Marston](https://github.com/myronmarston) who implemented this!
|
50
|
+
|
51
|
+
### Serializers
|
52
|
+
|
53
|
+
Before, serialization of Ruby objects into Riak was constrained to
|
54
|
+
three formats: JSON, YAML and Marshal. Now you can define your own
|
55
|
+
serializers so that you can store data in BSON, MsgPack, NetStrings,
|
56
|
+
or whatever format you like. Use `Riak::Serializers[content_type] =
|
57
|
+
serializer` to assign a serializer for the selected media type. The
|
58
|
+
serializer must respond to `#dump` and `#load`. (More handiwork of Myron
|
59
|
+
Marston, thanks!)
|
60
|
+
|
61
|
+
### Stamps
|
62
|
+
|
63
|
+
If you don't like the keys that Riak hands out when you store an
|
64
|
+
`RObject` without a key, and you want something naturally ordered, you
|
65
|
+
can now generate them client-side using `Riak::Stamp`, which will
|
66
|
+
generate 64-bit integers in a fashion similar to Twitter's Snowflake,
|
67
|
+
but uses `Riak::Client#client_id` as the machine identifier.
|
68
|
+
|
69
|
+
### Repository/Feature split
|
70
|
+
|
71
|
+
In an effort to decouple development of the individual projects and
|
72
|
+
reduce top-level dependencies, the `ripple` repository was split into
|
73
|
+
new repositories containing its corresponding sub-projects.
|
74
|
+
Additionally, the `Riak::CacheStore` has become its own project/gem.
|
75
|
+
The new gem and repository locations are below:
|
76
|
+
|
77
|
+
* [`riak-client`](http://rubygems.org/gems/riak-client) —
|
78
|
+
[basho/riak-ruby-client](https://github.com/basho/riak-ruby-client)
|
79
|
+
* [`ripple`](http://rubygems.org/gems/ripple) —
|
80
|
+
[seancribbs/ripple](https://github.com/seancribbs/ripple)
|
81
|
+
* [`riak-sessions`](http://rubygems.org/gems/riak-sessions) —
|
82
|
+
[seancribbs/riak-sessions](https://github.com/seancribbs/riak-sessions)
|
83
|
+
* [`riak-cache`](http://rubygems.org/gems/riak-cache) —
|
84
|
+
[seancribbs/riak-cache](https://github.com/seancribbs/riak-cache)
|
85
|
+
|
86
|
+
### Significant Known Issues
|
87
|
+
|
88
|
+
Attempting to use the Protocol Buffers transport with a 0.14.x cluster
|
89
|
+
may cause the connection to dump because of incompatibilities in
|
90
|
+
certain protocol messages. This will be addressed in a future
|
91
|
+
patch/bugfix release.
|
92
|
+
|
93
|
+
The new node generation and test server intermittently fails on JRuby,
|
94
|
+
specifically from deadlocks related to blocking opens for the console
|
95
|
+
FIFOs. The JRuby team has helped on this issue, but there may not be a
|
96
|
+
clear resolution path until JRuby 1.7 or later.
|
97
|
+
|
98
|
+
Other known issues may be found on the
|
99
|
+
[Github issue tracker](https://github.com/basho/riak-ruby-client/issues?milestone=1).
|
data/Rakefile
CHANGED
@@ -24,9 +24,28 @@ task :release => :gem do
|
|
24
24
|
system "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
25
25
|
end
|
26
26
|
|
27
|
+
desc "Cleans up white space in source files"
|
28
|
+
task :clean_whitespace do
|
29
|
+
no_file_cleaned = true
|
30
|
+
|
31
|
+
Dir["**/*.rb"].each do |file|
|
32
|
+
contents = File.read(file)
|
33
|
+
cleaned_contents = contents.gsub(/([ \t]+)$/, '')
|
34
|
+
unless cleaned_contents == contents
|
35
|
+
no_file_cleaned = false
|
36
|
+
puts " - Cleaned #{file}"
|
37
|
+
File.open(file, 'w') { |f| f.write(cleaned_contents) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
if no_file_cleaned
|
42
|
+
puts "No files with trailing whitespace found"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
27
46
|
desc "Run Unit Specs Only"
|
28
47
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
29
|
-
spec.rspec_opts = %w[--profile --tag ~integration]
|
48
|
+
spec.rspec_opts = %w[--profile --tag ~integration --tag ~slow]
|
30
49
|
end
|
31
50
|
|
32
51
|
namespace :spec do
|
@@ -39,6 +58,11 @@ namespace :spec do
|
|
39
58
|
RSpec::Core::RakeTask.new(:all) do |spec|
|
40
59
|
spec.rspec_opts = %w[--profile --tag '~slow']
|
41
60
|
end
|
61
|
+
|
62
|
+
desc "Run Slow Specs Only"
|
63
|
+
RSpec::Core::RakeTask.new(:slow) do |spec|
|
64
|
+
spec.rspec_opts = %w[--profile --tag slow]
|
65
|
+
end
|
42
66
|
end
|
43
67
|
|
44
68
|
desc "Run All Specs (including slow specs)"
|
Binary file
|
@@ -0,0 +1,189 @@
|
|
1
|
+
%% -------------------------------------------------------------------
|
2
|
+
%%
|
3
|
+
%% riak_kv_test_backend: storage engine based on ETS tables
|
4
|
+
%%
|
5
|
+
%% Copyright (c) 2007-2010 Basho Technologies, Inc. All Rights Reserved.
|
6
|
+
%%
|
7
|
+
%% This file is provided to you under the Apache License,
|
8
|
+
%% Version 2.0 (the "License"); you may not use this file
|
9
|
+
%% except in compliance with the License. You may obtain
|
10
|
+
%% a copy of the License at
|
11
|
+
%%
|
12
|
+
%% http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
%%
|
14
|
+
%% Unless required by applicable law or agreed to in writing,
|
15
|
+
%% software distributed under the License is distributed on an
|
16
|
+
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
17
|
+
%% KIND, either express or implied. See the License for the
|
18
|
+
%% specific language governing permissions and limitations
|
19
|
+
%% under the License.
|
20
|
+
%%
|
21
|
+
%% -------------------------------------------------------------------
|
22
|
+
|
23
|
+
% @doc riak_kv_test_backend is a Riak storage backend using ets that
|
24
|
+
% exposes a reset function for efficiently clearing stored data.
|
25
|
+
|
26
|
+
-module(riak_kv_test014_backend).
|
27
|
+
-behavior(riak_kv_backend).
|
28
|
+
-behavior(gen_server).
|
29
|
+
-ifdef(TEST).
|
30
|
+
-include_lib("eunit/include/eunit.hrl").
|
31
|
+
-endif.
|
32
|
+
-export([start/2,stop/1,get/2,put/3,list/1,list_bucket/2,delete/2,
|
33
|
+
is_empty/1, drop/1, fold/3, callback/3, reset/0]).
|
34
|
+
|
35
|
+
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
36
|
+
terminate/2, code_change/3]).
|
37
|
+
|
38
|
+
|
39
|
+
% @type state() = term().
|
40
|
+
-record(state, {t, p}).
|
41
|
+
|
42
|
+
% @spec start(Partition :: integer(), Config :: proplist()) ->
|
43
|
+
% {ok, state()} | {{error, Reason :: term()}, state()}
|
44
|
+
start(Partition, _Config) ->
|
45
|
+
gen_server:start_link(?MODULE, [Partition], []).
|
46
|
+
|
47
|
+
% @spec reset() -> ok | {error, timeout}
|
48
|
+
reset() ->
|
49
|
+
Pids = lists:foldl(fun(Item, Acc) ->
|
50
|
+
case lists:prefix("test_backend", atom_to_list(Item)) of
|
51
|
+
true -> [whereis(Item)|Acc];
|
52
|
+
_ -> Acc
|
53
|
+
end
|
54
|
+
end, [], registered()),
|
55
|
+
[gen_server:cast(Pid,{reset, self()})|| Pid <- Pids],
|
56
|
+
receive_reset(Pids).
|
57
|
+
|
58
|
+
receive_reset([]) -> ok;
|
59
|
+
receive_reset(Pids) ->
|
60
|
+
receive
|
61
|
+
{reset, Pid} ->
|
62
|
+
receive_reset(lists:delete(Pid, Pids))
|
63
|
+
after 1000 ->
|
64
|
+
{error, timeout}
|
65
|
+
end.
|
66
|
+
|
67
|
+
%% @private
|
68
|
+
init([Partition]) ->
|
69
|
+
PName = list_to_atom("test_backend" ++ integer_to_list(Partition)),
|
70
|
+
P = list_to_atom(integer_to_list(Partition)),
|
71
|
+
register(PName, self()),
|
72
|
+
{ok, #state{t=ets:new(P,[]), p=P}}.
|
73
|
+
|
74
|
+
%% @private
|
75
|
+
handle_cast({reset,From}, State) ->
|
76
|
+
ets:delete_all_objects(State#state.t),
|
77
|
+
From ! {reset, self()},
|
78
|
+
{noreply, State};
|
79
|
+
handle_cast(_, State) -> {noreply, State}.
|
80
|
+
|
81
|
+
%% @private
|
82
|
+
handle_call(stop,_From,State) -> {reply, srv_stop(State), State};
|
83
|
+
handle_call({get,BKey},_From,State) -> {reply, srv_get(State,BKey), State};
|
84
|
+
handle_call({put,BKey,Val},_From,State) ->
|
85
|
+
{reply, srv_put(State,BKey,Val),State};
|
86
|
+
handle_call({delete,BKey},_From,State) -> {reply, srv_delete(State,BKey),State};
|
87
|
+
handle_call(list,_From,State) -> {reply, srv_list(State), State};
|
88
|
+
handle_call({list_bucket,Bucket},_From,State) ->
|
89
|
+
{reply, srv_list_bucket(State, Bucket), State};
|
90
|
+
handle_call(is_empty, _From, State) ->
|
91
|
+
{reply, ets:info(State#state.t, size) =:= 0, State};
|
92
|
+
handle_call(drop, _From, State) ->
|
93
|
+
ets:delete(State#state.t),
|
94
|
+
{reply, ok, State};
|
95
|
+
handle_call({fold, Fun0, Acc}, _From, State) ->
|
96
|
+
Fun = fun({{B,K}, V}, AccIn) -> Fun0({B,K}, V, AccIn) end,
|
97
|
+
Reply = ets:foldl(Fun, Acc, State#state.t),
|
98
|
+
{reply, Reply, State}.
|
99
|
+
|
100
|
+
% @spec stop(state()) -> ok | {error, Reason :: term()}
|
101
|
+
stop(SrvRef) -> gen_server:call(SrvRef,stop).
|
102
|
+
srv_stop(State) ->
|
103
|
+
true = ets:delete(State#state.t),
|
104
|
+
ok.
|
105
|
+
|
106
|
+
% get(state(), riak_object:bkey()) ->
|
107
|
+
% {ok, Val :: binary()} | {error, Reason :: term()}
|
108
|
+
% key must be 160b
|
109
|
+
get(SrvRef, BKey) -> gen_server:call(SrvRef,{get,BKey}).
|
110
|
+
srv_get(State, BKey) ->
|
111
|
+
case ets:lookup(State#state.t,BKey) of
|
112
|
+
[] -> {error, notfound};
|
113
|
+
[{BKey,Val}] -> {ok, Val};
|
114
|
+
Err -> {error, Err}
|
115
|
+
end.
|
116
|
+
|
117
|
+
% put(state(), riak_object:bkey(), Val :: binary()) ->
|
118
|
+
% ok | {error, Reason :: term()}
|
119
|
+
% key must be 160b
|
120
|
+
put(SrvRef, BKey, Val) -> gen_server:call(SrvRef,{put,BKey,Val}).
|
121
|
+
srv_put(State,BKey,Val) ->
|
122
|
+
true = ets:insert(State#state.t, {BKey,Val}),
|
123
|
+
ok.
|
124
|
+
|
125
|
+
% delete(state(), riak_object:bkey()) ->
|
126
|
+
% ok | {error, Reason :: term()}
|
127
|
+
% key must be 160b
|
128
|
+
delete(SrvRef, BKey) -> gen_server:call(SrvRef,{delete,BKey}).
|
129
|
+
srv_delete(State, BKey) ->
|
130
|
+
true = ets:delete(State#state.t, BKey),
|
131
|
+
ok.
|
132
|
+
|
133
|
+
% list(state()) -> [riak_object:bkey()]
|
134
|
+
list(SrvRef) -> gen_server:call(SrvRef,list).
|
135
|
+
srv_list(State) ->
|
136
|
+
MList = ets:match(State#state.t,{'$1','_'}),
|
137
|
+
list(MList,[]).
|
138
|
+
list([],Acc) -> Acc;
|
139
|
+
list([[K]|Rest],Acc) -> list(Rest,[K|Acc]).
|
140
|
+
|
141
|
+
% list_bucket(term(), Bucket :: riak_object:bucket()) -> [Key :: binary()]
|
142
|
+
list_bucket(SrvRef, Bucket) ->
|
143
|
+
gen_server:call(SrvRef,{list_bucket, Bucket}).
|
144
|
+
srv_list_bucket(State, {filter, Bucket, Fun}) ->
|
145
|
+
MList = lists:filter(Fun, ets:match(State#state.t,{{Bucket,'$1'},'_'})),
|
146
|
+
list(MList,[]);
|
147
|
+
srv_list_bucket(State, Bucket) ->
|
148
|
+
case Bucket of
|
149
|
+
'_' -> MatchSpec = {{'$1','_'},'_'};
|
150
|
+
_ -> MatchSpec = {{Bucket,'$1'},'_'}
|
151
|
+
end,
|
152
|
+
MList = ets:match(State#state.t,MatchSpec),
|
153
|
+
list(MList,[]).
|
154
|
+
|
155
|
+
is_empty(SrvRef) -> gen_server:call(SrvRef, is_empty).
|
156
|
+
|
157
|
+
drop(SrvRef) -> gen_server:call(SrvRef, drop).
|
158
|
+
|
159
|
+
fold(SrvRef, Fun, Acc0) -> gen_server:call(SrvRef, {fold, Fun, Acc0}, infinity).
|
160
|
+
|
161
|
+
%% Ignore callbacks for other backends so multi backend works
|
162
|
+
callback(_State, _Ref, _Msg) ->
|
163
|
+
ok.
|
164
|
+
|
165
|
+
%% @private
|
166
|
+
handle_info(_Msg, State) -> {noreply, State}.
|
167
|
+
|
168
|
+
%% @private
|
169
|
+
terminate(_Reason, _State) -> ok.
|
170
|
+
|
171
|
+
%% @private
|
172
|
+
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
173
|
+
|
174
|
+
%%
|
175
|
+
%% Test
|
176
|
+
%%
|
177
|
+
-ifdef(TEST).
|
178
|
+
|
179
|
+
% @private
|
180
|
+
simple_test() ->
|
181
|
+
riak_kv_backend:standard_test(?MODULE, []).
|
182
|
+
|
183
|
+
-ifdef(EQC).
|
184
|
+
%% @private
|
185
|
+
eqc_test() ->
|
186
|
+
?assertEqual(true, backend_eqc:test(?MODULE, true)).
|
187
|
+
|
188
|
+
-endif. % EQC
|
189
|
+
-endif. % TEST
|