diff options
author | Garren Smith <garren.smith@gmail.com> | 2018-06-21 16:30:35 +0200 |
---|---|---|
committer | Robert Newson <rnewson@apache.org> | 2018-10-01 17:32:58 +0100 |
commit | 7adfb1f417cf7026ca0d33b98d1a153265c0f095 (patch) | |
tree | 6547ee2e46a0e590f3b38741f142dbebfcbe81f4 | |
parent | fbb5588e2d023eb1bcf97cf9e44d483de2b2a62d (diff) | |
download | couchdb-7adfb1f417cf7026ca0d33b98d1a153265c0f095.tar.gz |
Add a generic 'props' list at db creation time
This props list is recorded in each database shard as well as the
shard document in the special _dbs database.
Co-authored-by: Garren Smith <garren.smith@gmail.com>
Co-authored-by: Robert Newson <rnewson@apache.org>
-rw-r--r-- | src/couch/src/couch_bt_engine.erl | 73 | ||||
-rw-r--r-- | src/couch/src/couch_bt_engine_compactor.erl | 8 | ||||
-rw-r--r-- | src/couch/src/couch_bt_engine_header.erl | 3 | ||||
-rw-r--r-- | src/couch/src/couch_db.erl | 11 | ||||
-rw-r--r-- | src/couch/src/couch_db_engine.erl | 47 | ||||
-rw-r--r-- | src/couch/src/couch_db_int.hrl | 3 | ||||
-rw-r--r-- | src/couch/src/couch_db_updater.erl | 11 | ||||
-rw-r--r-- | src/fabric/src/fabric_db_create.erl | 6 | ||||
-rw-r--r-- | src/mem3/src/mem3_util.erl | 12 |
9 files changed, 163 insertions, 11 deletions
diff --git a/src/couch/src/couch_bt_engine.erl b/src/couch/src/couch_bt_engine.erl index 6d858ed49..abeaeaaa7 100644 --- a/src/couch/src/couch_bt_engine.erl +++ b/src/couch/src/couch_bt_engine.erl @@ -40,6 +40,9 @@ get_purge_infos_limit/1, get_revs_limit/1, get_security/1, + get_props/1, + get_prop/2, + get_prop/3, get_size_info/1, get_update_seq/1, get_uuid/1, @@ -47,6 +50,7 @@ set_revs_limit/2, set_purge_infos_limit/2, set_security/2, + set_prop/3, open_docs/2, open_local_docs/2, @@ -104,7 +108,8 @@ -export([ set_update_seq/2, update_header/2, - copy_security/2 + copy_security/2, + copy_props/2 ]). @@ -143,8 +148,9 @@ init(FilePath, Options) -> true -> delete_compaction_files(FilePath), Header0 = couch_bt_engine_header:new(), - ok = couch_file:write_header(Fd, Header0), - Header0; + Header1 = set_initial_props(Fd, Header0, Options), + ok = couch_file:write_header(Fd, Header1), + Header1; false -> case couch_file:read_header(Fd) of {ok, Header0} -> @@ -283,6 +289,31 @@ get_security(#st{header = Header} = St) -> end. +get_props(#st{header = Header} = St) -> + case couch_bt_engine_header:get(Header, props_ptr) of + undefined -> + []; + Pointer -> + {ok, Props} = couch_file:pread_term(St#st.fd, Pointer), + Props + end. + + +get_prop(St, Key) -> + Props = get_props(St), + case lists:keyfind(Key, 1, Props) of + false -> {error, no_value}; + {Key, Value} -> {ok, Value} + end. + + +get_prop(St, Key, DefaultValue) -> + case get_prop(St, Key) of + {error, no_value} -> DefaultValue; + Value -> Value + end. + + get_update_seq(#st{header = Header}) -> couch_bt_engine_header:get(Header, update_seq). @@ -323,6 +354,20 @@ set_security(#st{header = Header} = St, NewSecurity) -> {ok, increment_update_seq(NewSt)}. +set_prop(#st{header = Header} = St, Key, Value) -> + OldProps = get_props(St), + NewProps = lists:ukeymerge(1, [{Key, Value}], OldProps), + Options = [{compression, St#st.compression}], + {ok, Ptr, _} = couch_file:append_term(St#st.fd, NewProps, Options), + NewSt = St#st{ + header = couch_bt_engine_header:set(Header, [ + {props_ptr, Ptr} + ]), + needs_commit = true + }, + {ok, increment_update_seq(NewSt)}. + + open_docs(#st{} = St, DocIds) -> Results = couch_btree:lookup(St#st.id_tree, DocIds), lists:map(fun @@ -752,6 +797,16 @@ copy_security(#st{header = Header} = St, SecProps) -> needs_commit = true }}. +copy_props(#st{header = Header} = St, Props) -> + Options = [{compression, St#st.compression}], + {ok, Ptr, _} = couch_file:append_term(St#st.fd, Props, Options), + {ok, St#st{ + header = couch_bt_engine_header:set(Header, [ + {props_ptr, Ptr} + ]), + needs_commit = true + }}. + open_db_file(FilePath, Options) -> case couch_file:open(FilePath, Options) of @@ -939,6 +994,18 @@ upgrade_purge_info(Fd, Header) -> end. +set_initial_props(Fd, Header, Options) -> + case couch_util:get_value(initial_props, Options) of + undefined -> + Header; + InitialProps -> + Compression = couch_compress:get_compression_method(), + AppendOpts = [{compression, Compression}], + {ok, Ptr, _} = couch_file:append_term(Fd, InitialProps, AppendOpts), + couch_bt_engine_header:set(Header, props_ptr, Ptr) + end. + + delete_compaction_files(FilePath) -> RootDir = config:get("couchdb", "database_dir", "."), DelOpts = [{context, compaction}], diff --git a/src/couch/src/couch_bt_engine_compactor.erl b/src/couch/src/couch_bt_engine_compactor.erl index 10de68687..4e68dd171 100644 --- a/src/couch/src/couch_bt_engine_compactor.erl +++ b/src/couch/src/couch_bt_engine_compactor.erl @@ -276,9 +276,13 @@ copy_compact(DbName, St, NewSt0, Retry) -> SecProps = couch_bt_engine:get_security(St), {ok, NewSt4} = couch_bt_engine:copy_security(NewSt3, SecProps), + % Copy general properties over + Props = couch_bt_engine:get_props(St), + {ok, NewSt5} = couch_bt_engine:copy_props(NewSt4, Props), + FinalUpdateSeq = couch_bt_engine:get_update_seq(St), - {ok, NewSt5} = couch_bt_engine:set_update_seq(NewSt4, FinalUpdateSeq), - commit_compaction_data(NewSt5). + {ok, NewSt6} = couch_bt_engine:set_update_seq(NewSt5, FinalUpdateSeq), + commit_compaction_data(NewSt6). copy_docs(St, #st{} = NewSt, MixedInfos, Retry) -> diff --git a/src/couch/src/couch_bt_engine_header.erl b/src/couch/src/couch_bt_engine_header.erl index 467bb2ff8..7f701fca2 100644 --- a/src/couch/src/couch_bt_engine_header.erl +++ b/src/couch/src/couch_bt_engine_header.erl @@ -68,7 +68,8 @@ uuid, epochs, compacted_seq, - purge_infos_limit = 1000 + purge_infos_limit = 1000, + props_ptr }). diff --git a/src/couch/src/couch_db.erl b/src/couch/src/couch_db.erl index 55664e964..d6e512864 100644 --- a/src/couch/src/couch_db.erl +++ b/src/couch/src/couch_db.erl @@ -46,6 +46,7 @@ get_pid/1, get_revs_limit/1, get_security/1, + get_props/1, get_update_seq/1, get_user_ctx/1, get_uuid/1, @@ -60,6 +61,7 @@ set_revs_limit/2, set_purge_infos_limit/2, set_security/2, + set_prop/3, set_user_ctx/2, ensure_full_commit/1, @@ -714,6 +716,15 @@ set_security(#db{main_pid=Pid}=Db, {NewSecProps}) when is_list(NewSecProps) -> set_security(_, _) -> throw(bad_request). +get_props(#db{props=Props}) -> + Props. + +set_prop(#db{main_pid=Pid}=Db, Key, Value) -> + check_is_admin(Db), + ok = gen_server:call(Pid, {set_prop, Key, Value}, infinity), + {ok, _} = ensure_full_commit(Db), + ok. + set_user_ctx(#db{} = Db, UserCtx) -> {ok, Db#db{user_ctx = UserCtx}}. diff --git a/src/couch/src/couch_db_engine.erl b/src/couch/src/couch_db_engine.erl index ea30dbc77..85a3cb5d2 100644 --- a/src/couch/src/couch_db_engine.erl +++ b/src/couch/src/couch_db_engine.erl @@ -242,6 +242,19 @@ % the last value that was passed to set_security/2. -callback get_security(DbHandle::db_handle()) -> SecProps::any(). +% Get the current properties. +-callback get_props(DbHandle::db_handle()) -> Props::any(). + +% Get the current properties. This should just return +% the last value that was passed to set_prop/2. +-callback get_prop(DbHandle::db_handle(), Prop::atom()) -> + {ok, SecProps::json()} | {error, no_value}. + +% Get the current properties. If the value isn't set it will return the set default value. +% This should just return the last value that was passed to set_prop/2. +-callback get_prop(DbHandle::db_handle(), Prop::atom(), DefaultValue::any()) -> + {ok, SecProps::json()}. + % This information is displayed in the database info poperties. It % should just be a list of {Name::atom(), Size::non_neg_integer()} @@ -288,6 +301,15 @@ {ok, NewDbHandle::db_handle()}. +% This function is only called by couch_db_updater and +% as such is guaranteed to be single threaded calls. The +% database should simply store prop key and value somewhere so +% they can be returned by the corresponding get_prop calls. + +-callback set_prop(DbHandle::db_handle(), PropKey::atom(), PropValue::any()) -> + {ok, NewDbHandle::db_handle()}. + + % This function will be called by many processes concurrently. % It should return a #full_doc_info{} record or not_found for % every provided DocId in the order those DocId's appear in @@ -670,6 +692,9 @@ get_purge_infos_limit/1, get_revs_limit/1, get_security/1, + get_props/1, + get_prop/2, + get_prop/3, get_size_info/1, get_update_seq/1, get_uuid/1, @@ -677,6 +702,7 @@ set_revs_limit/2, set_security/2, set_purge_infos_limit/2, + set_prop/3, open_docs/2, open_local_docs/2, @@ -836,6 +862,21 @@ get_security(#db{} = Db) -> Engine:get_security(EngineState). +get_props(#db{} = Db) -> + #db{engine = {Engine, EngineState}} = Db, + Engine:get_props(EngineState). + + +get_prop(#db{} = Db, Prop) -> + #db{engine = {Engine, EngineState}} = Db, + Engine:get_prop(EngineState, Prop). + + +get_prop(#db{} = Db, Prop, DefaultValue) -> + #db{engine = {Engine, EngineState}} = Db, + Engine:get_prop(EngineState, Prop, DefaultValue). + + get_size_info(#db{} = Db) -> #db{engine = {Engine, EngineState}} = Db, Engine:get_size_info(EngineState). @@ -868,6 +909,12 @@ set_security(#db{} = Db, SecProps) -> {ok, Db#db{engine = {Engine, NewSt}}}. +set_prop(#db{} = Db, Key, Value) -> + #db{engine = {Engine, EngineState}} = Db, + {ok, NewSt} = Engine:set_prop(EngineState, Key, Value), + {ok, Db#db{engine = {Engine, NewSt}}}. + + open_docs(#db{} = Db, DocIds) -> #db{engine = {Engine, EngineState}} = Db, Engine:open_docs(EngineState, DocIds). diff --git a/src/couch/src/couch_db_int.hrl b/src/couch/src/couch_db_int.hrl index a412b338b..f2a8e17f5 100644 --- a/src/couch/src/couch_db_int.hrl +++ b/src/couch/src/couch_db_int.hrl @@ -35,7 +35,8 @@ waiting_delayed_commit = nil, options = [], - compression + compression, + props = [] }). diff --git a/src/couch/src/couch_db_updater.erl b/src/couch/src/couch_db_updater.erl index 52a4d2f1b..687fb7991 100644 --- a/src/couch/src/couch_db_updater.erl +++ b/src/couch/src/couch_db_updater.erl @@ -88,6 +88,14 @@ handle_call({set_security, NewSec}, _From, #db{} = Db) -> ok = gen_server:call(couch_server, {db_updated, NewSecDb}, infinity), {reply, ok, NewSecDb, idle_limit()}; +handle_call({set_prop, Key, Value}, _From, #db{} = Db) -> + {ok, NewDb} = couch_db_engine:set_prop(Db, Key, Value), + NewPropDb = commit_data(NewDb#db{ + props = couch_db_engine:get_props(NewDb) + }), + ok = gen_server:call(couch_server, {db_updated, NewPropDb}, infinity), + {reply, ok, NewPropDb, idle_limit()}; + handle_call({set_revs_limit, Limit}, _From, Db) -> {ok, Db2} = couch_db_engine:set_revs_limit(Db, Limit), Db3 = commit_data(Db2), @@ -324,7 +332,8 @@ init_db(DbName, FilePath, EngineState, Options) -> InitDb#db{ committed_update_seq = couch_db_engine:get_update_seq(InitDb), - security = couch_db_engine:get_security(InitDb) + security = couch_db_engine:get_security(InitDb), + props = couch_db_engine:get_props(InitDb) }. diff --git a/src/fabric/src/fabric_db_create.erl b/src/fabric/src/fabric_db_create.erl index 94ffd5643..90ccdab86 100644 --- a/src/fabric/src/fabric_db_create.erl +++ b/src/fabric/src/fabric_db_create.erl @@ -164,6 +164,10 @@ make_document([#shard{dbname=DbName}|_] = Shards, Suffix, Options) -> {[[<<"add">>, Range, Node] | Raw], orddict:append(Node, Range, ByNode), orddict:append(Range, Node, ByRange)} end, {[], [], []}, Shards), + InitialProps = case couch_util:get_value(initial_props, Options) of + I when is_list(I) -> [{<<"options">>, {I}}]; + _ -> [] + end, EngineProp = case couch_util:get_value(engine, Options) of E when is_binary(E) -> [{<<"engine">>, E}]; _ -> [] @@ -175,7 +179,7 @@ make_document([#shard{dbname=DbName}|_] = Shards, Suffix, Options) -> {<<"changelog">>, lists:sort(RawOut)}, {<<"by_node">>, {[{K,lists:sort(V)} || {K,V} <- ByNodeOut]}}, {<<"by_range">>, {[{K,lists:sort(V)} || {K,V} <- ByRangeOut]}} - ] ++ EngineProp} + ] ++ EngineProp ++ InitialProps} }. db_exists(DbName) -> is_list(catch mem3:shards(DbName)). diff --git a/src/mem3/src/mem3_util.erl b/src/mem3/src/mem3_util.erl index 254a6dfa6..8cf67cb66 100644 --- a/src/mem3/src/mem3_util.erl +++ b/src/mem3/src/mem3_util.erl @@ -162,7 +162,7 @@ build_shards_by_node(DbName, DocProps) -> dbname = DbName, node = to_atom(Node), range = [Beg, End], - opts = get_engine_opt(DocProps) + opts = get_engine_opt(DocProps) ++ get_opts(DocProps) }, Suffix) end, Ranges) end, ByNode). @@ -180,7 +180,7 @@ build_shards_by_range(DbName, DocProps) -> node = to_atom(Node), range = [Beg, End], order = Order, - opts = get_engine_opt(DocProps) + opts = get_engine_opt(DocProps) ++ get_opts(DocProps) }, Suffix) end, lists:zip(Nodes, lists:seq(1, length(Nodes)))) end, ByRange). @@ -197,6 +197,14 @@ to_integer(N) when is_binary(N) -> to_integer(N) when is_list(N) -> list_to_integer(N). +get_opts(DocProps) -> + case couch_util:get_value(<<"options">>, DocProps) of + {Opts} -> + Opts; + _ -> + [] + end. + get_engine_opt(DocProps) -> case couch_util:get_value(<<"engine">>, DocProps) of Engine when is_binary(Engine) -> |