Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Make compatibility adjustments for 0.14.x.

  • Loading branch information...
commit cb20fb0f48836348ddfaab9dae390160cb3f0689 1 parent be54f0b
Sean Cribbs authored
View
BIN  erl_src/riak_kv_test014_backend.beam
Binary file not shown
View
189 erl_src/riak_kv_test014_backend.erl
@@ -0,0 +1,189 @@
+%% -------------------------------------------------------------------
+%%
+%% riak_kv_test_backend: storage engine based on ETS tables
+%%
+%% Copyright (c) 2007-2010 Basho Technologies, Inc. All Rights Reserved.
+%%
+%% This file is provided to you 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
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% 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.
+%%
+%% -------------------------------------------------------------------
+
+% @doc riak_kv_test_backend is a Riak storage backend using ets that
+% exposes a reset function for efficiently clearing stored data.
+
+-module(riak_kv_test014_backend).
+-behavior(riak_kv_backend).
+-behavior(gen_server).
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+-endif.
+-export([start/2,stop/1,get/2,put/3,list/1,list_bucket/2,delete/2,
+ is_empty/1, drop/1, fold/3, callback/3, reset/0]).
+
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+
+% @type state() = term().
+-record(state, {t, p}).
+
+% @spec start(Partition :: integer(), Config :: proplist()) ->
+% {ok, state()} | {{error, Reason :: term()}, state()}
+start(Partition, _Config) ->
+ gen_server:start_link(?MODULE, [Partition], []).
+
+% @spec reset() -> ok | {error, timeout}
+reset() ->
+ Pids = lists:foldl(fun(Item, Acc) ->
+ case lists:prefix("test_backend", atom_to_list(Item)) of
+ true -> [whereis(Item)|Acc];
+ _ -> Acc
+ end
+ end, [], registered()),
+ [gen_server:cast(Pid,{reset, self()})|| Pid <- Pids],
+ receive_reset(Pids).
+
+receive_reset([]) -> ok;
+receive_reset(Pids) ->
+ receive
+ {reset, Pid} ->
+ receive_reset(lists:delete(Pid, Pids))
+ after 1000 ->
+ {error, timeout}
+ end.
+
+%% @private
+init([Partition]) ->
+ PName = list_to_atom("test_backend" ++ integer_to_list(Partition)),
+ P = list_to_atom(integer_to_list(Partition)),
+ register(PName, self()),
+ {ok, #state{t=ets:new(P,[]), p=P}}.
+
+%% @private
+handle_cast({reset,From}, State) ->
+ ets:delete_all_objects(State#state.t),
+ From ! {reset, self()},
+ {noreply, State};
+handle_cast(_, State) -> {noreply, State}.
+
+%% @private
+handle_call(stop,_From,State) -> {reply, srv_stop(State), State};
+handle_call({get,BKey},_From,State) -> {reply, srv_get(State,BKey), State};
+handle_call({put,BKey,Val},_From,State) ->
+ {reply, srv_put(State,BKey,Val),State};
+handle_call({delete,BKey},_From,State) -> {reply, srv_delete(State,BKey),State};
+handle_call(list,_From,State) -> {reply, srv_list(State), State};
+handle_call({list_bucket,Bucket},_From,State) ->
+ {reply, srv_list_bucket(State, Bucket), State};
+handle_call(is_empty, _From, State) ->
+ {reply, ets:info(State#state.t, size) =:= 0, State};
+handle_call(drop, _From, State) ->
+ ets:delete(State#state.t),
+ {reply, ok, State};
+handle_call({fold, Fun0, Acc}, _From, State) ->
+ Fun = fun({{B,K}, V}, AccIn) -> Fun0({B,K}, V, AccIn) end,
+ Reply = ets:foldl(Fun, Acc, State#state.t),
+ {reply, Reply, State}.
+
+% @spec stop(state()) -> ok | {error, Reason :: term()}
+stop(SrvRef) -> gen_server:call(SrvRef,stop).
+srv_stop(State) ->
+ true = ets:delete(State#state.t),
+ ok.
+
+% get(state(), riak_object:bkey()) ->
+% {ok, Val :: binary()} | {error, Reason :: term()}
+% key must be 160b
+get(SrvRef, BKey) -> gen_server:call(SrvRef,{get,BKey}).
+srv_get(State, BKey) ->
+ case ets:lookup(State#state.t,BKey) of
+ [] -> {error, notfound};
+ [{BKey,Val}] -> {ok, Val};
+ Err -> {error, Err}
+ end.
+
+% put(state(), riak_object:bkey(), Val :: binary()) ->
+% ok | {error, Reason :: term()}
+% key must be 160b
+put(SrvRef, BKey, Val) -> gen_server:call(SrvRef,{put,BKey,Val}).
+srv_put(State,BKey,Val) ->
+ true = ets:insert(State#state.t, {BKey,Val}),
+ ok.
+
+% delete(state(), riak_object:bkey()) ->
+% ok | {error, Reason :: term()}
+% key must be 160b
+delete(SrvRef, BKey) -> gen_server:call(SrvRef,{delete,BKey}).
+srv_delete(State, BKey) ->
+ true = ets:delete(State#state.t, BKey),
+ ok.
+
+% list(state()) -> [riak_object:bkey()]
+list(SrvRef) -> gen_server:call(SrvRef,list).
+srv_list(State) ->
+ MList = ets:match(State#state.t,{'$1','_'}),
+ list(MList,[]).
+list([],Acc) -> Acc;
+list([[K]|Rest],Acc) -> list(Rest,[K|Acc]).
+
+% list_bucket(term(), Bucket :: riak_object:bucket()) -> [Key :: binary()]
+list_bucket(SrvRef, Bucket) ->
+ gen_server:call(SrvRef,{list_bucket, Bucket}).
+srv_list_bucket(State, {filter, Bucket, Fun}) ->
+ MList = lists:filter(Fun, ets:match(State#state.t,{{Bucket,'$1'},'_'})),
+ list(MList,[]);
+srv_list_bucket(State, Bucket) ->
+ case Bucket of
+ '_' -> MatchSpec = {{'$1','_'},'_'};
+ _ -> MatchSpec = {{Bucket,'$1'},'_'}
+ end,
+ MList = ets:match(State#state.t,MatchSpec),
+ list(MList,[]).
+
+is_empty(SrvRef) -> gen_server:call(SrvRef, is_empty).
+
+drop(SrvRef) -> gen_server:call(SrvRef, drop).
+
+fold(SrvRef, Fun, Acc0) -> gen_server:call(SrvRef, {fold, Fun, Acc0}, infinity).
+
+%% Ignore callbacks for other backends so multi backend works
+callback(_State, _Ref, _Msg) ->
+ ok.
+
+%% @private
+handle_info(_Msg, State) -> {noreply, State}.
+
+%% @private
+terminate(_Reason, _State) -> ok.
+
+%% @private
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
+
+%%
+%% Test
+%%
+-ifdef(TEST).
+
+% @private
+simple_test() ->
+ riak_kv_backend:standard_test(?MODULE, []).
+
+-ifdef(EQC).
+%% @private
+eqc_test() ->
+ ?assertEqual(true, backend_eqc:test(?MODULE, true)).
+
+-endif. % EQC
+-endif. % TEST
View
12 lib/riak/test_server.rb
@@ -17,7 +17,6 @@ def initialize(configuration = {})
configuration[:env] ||= {}
configuration[:env][:riak_kv] ||= {}
(configuration[:env][:riak_kv][:add_paths] ||= []) << File.expand_path("../../../erl_src", __FILE__)
- configuration[:env][:riak_kv][:storage_backend] = :riak_kv_test_backend
configuration[:env][:riak_search] ||= {}
configuration[:env][:riak_search][:search_backend] = :riak_search_test_backend
super configuration
@@ -52,7 +51,7 @@ def stop
def drop
begin
maybe_attach
- @console.command "riak_kv_test_backend:reset()."
+ @console.command "#{kv_backend}:reset()."
@console.command "riak_search_test_backend:reset()."
rescue IOError
retry
@@ -71,5 +70,14 @@ def maybe_attach
def open?
@console && @console.open?
end
+
+ def configure_data
+ super
+ if version < "1.0.0"
+ env[:riak_kv][:storage_backend] = :riak_kv_test014_backend
+ else
+ env[:riak_kv][:storage_backend] = :riak_kv_test_backend
+ end
+ end
end
end
View
7 spec/integration/riak/test_server_spec.rb
@@ -12,9 +12,10 @@
end
it "should use the KV test backend" do
- subject.kv_backend.should == :riak_kv_test_backend
- subject.env[:riak_kv][:storage_backend].should == :riak_kv_test_backend
- app_config.should include("{storage_backend, riak_kv_test_backend}")
+ backend = subject.version < "1.0.0" ? :riak_kv_test014_backend : :riak_kv_test_backend
+ subject.kv_backend.should == backend
+ subject.env[:riak_kv][:storage_backend].should == backend
+ app_config.should include("{storage_backend, #{backend}}")
end
it "should use the Search test backend" do
View
8 spec/integration/riak/threading_spec.rb
@@ -1,9 +1,6 @@
require 'spec_helper'
describe "Multithreaded client", :test_server => true do
- before(:all) do
- end
-
class Synchronizer
def initialize(n)
@mutex = Mutex.new
@@ -104,7 +101,10 @@ def threads(n, opts = {})
end
end
- it 'should put conflicts in parallel' do
+ # This is a 1.0+ spec because putting with the same client ID
+ # will not create siblings on 0.14 in the same way. This will
+ # also likely fail for nodes with vnode_vclocks = false.
+ it 'should put conflicts in parallel', :version => "1.0.0" do
@client['test'].allow_mult = true
@client['test'].allow_mult.should == true
View
1  spec/spec_helper.rb
@@ -10,6 +10,7 @@
Riak.disable_list_keys_warnings = true
%w[integration_setup
+ version_filter
http_backend_implementation_examples
unified_backend_examples
mocks
View
18 spec/support/unified_backend_examples.rb
@@ -9,7 +9,6 @@
context "fetching an object" do
before do
@robject = Riak::RObject.new(@client.bucket("test"), "fetch")
- @robject.indexes['test_bin'] << 'pass'
@robject.content_type = "application/json"
@robject.data = { "test" => "pass" }
@backend.store_object(@robject)
@@ -38,15 +37,18 @@
robj.data.should == { "test" => "pass" }
end
- it "should accept a PR value of #{q.inspect} for the request" do
+ it "should accept a PR value of #{q.inspect} for the request", :version => "1.0.0" do
robj = @backend.fetch_object("test", "fetch", :pr => q)
robj.should be_kind_of(Riak::RObject)
robj.data.should == { "test" => "pass" }
end
end
- it "should marshal indexes properly" do
+ it "should marshal indexes properly", :version => "1.0.0" do
# This really tests both storing and fetching indexes, given the setup
+ @robject.indexes['test_bin'] << 'pass'
+ @backend.store_object(@robject)
+
robj = @backend.fetch_object('test', 'fetch')
robj.indexes['test_bin'].should be
robj.indexes['test_bin'].should include('pass')
@@ -74,14 +76,16 @@
@backend.reload_object(@robject, :r => q)
end
- it "should accept a valid PR value of #{q.inspect} for the request" do
+ it "should accept a valid PR value of #{q.inspect} for the request", :version => "1.0.0" do
@backend.reload_object(@robject, :pr => q)
end
end
after do
- @robject.vclock.should == @robject2.vclock
- @robject.data['test'].should == "second"
+ unless example.pending?
+ @robject.vclock.should == @robject2.vclock
+ @robject.data['test'].should == "second"
+ end
end
end
@@ -112,7 +116,7 @@
@backend.store_object(@robject, :returnbody => false, :w => :all, :dw => q)
end
- it "should accept a PW value of #{q.inspect} for the request" do
+ it "should accept a PW value of #{q.inspect} for the request", :version => "1.0.0" do
@backend.store_object(@robject, :returnbody => false, :pw => q)
end
end
View
9 spec/support/version_filter.rb
@@ -0,0 +1,9 @@
+RSpec.configure do |config|
+ config.before(:each) do
+ if respond_to?(:test_server) && example.metadata[:test_server] != false && example.metadata[:version]
+ required = example.metadata[:version]
+ actual = test_server.version
+ pending("SKIP: Tests feature for Riak #{required}, but testing against #{actual}") if actual < required
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.