diff --git a/storage/src/storage.erl b/storage/src/storage.erl index 9b94034..411998a 100644 --- a/storage/src/storage.erl +++ b/storage/src/storage.erl @@ -46,9 +46,11 @@ file: -export([start_link/0]). % Public bucket operation functions --export([add_node/1, create/1, create/2, create/3, - grow/1, grow/2, grow/3, remove/1, - remove/2, shrink/1, shrink/2]). +-export([add_node/1, add_replica/2, add_replica/3, + create/1, create/2, create/3, + delete_replica/2, grow/1, grow/2, grow/3, + move/3, remove/1, remove/2, shrink/1, + shrink/2]). % Public record operation functions -export([delete/2, list/2, read/2, write/3, write/4]). @@ -111,6 +113,59 @@ Bootstrap and add the node `b@piwa` to the storage cluster. add_node(Node) -> gen_server:call(?MODULE, {node, Node}). +-doc """ +Create a replica of the given `Bucket` on `Node`. + +Spec: + +``` +-spec add_replica(Bucket, Node, Type) -> ok | {error, Reason} when + Bucket :: atom(), + Node :: atom(), + Type :: disc_copies | disc_only_copies | ram_copies, + Reason :: term(). +``` + +`Type` determines the kind of replica the destination node will manage, +be it on disc, RAM, or both. The possible values for `Type` means: + +- ram_copies: the replica will be kept only in RAM on the destination node. +- disc_copies: the replica will be in RAM and also on disc. +- disc_only_copies: the replica will reside on disc only. + +Example: + +Add a disk-only replica of the bucket "objects", on the node "pri@lab": + +``` +add_replica(objects, 'pri@lab', disc_only_copies). +ok +``` +""". +-spec add_replica(Bucket, Node, Type) -> ok | {error, Reason} when + Bucket :: atom(), + Node :: atom(), + Type :: disc_copies | disc_only_copies | ram_copies, + Reason :: term(). + +add_replica(Bucket, Node, Type) -> + gen_server:call(?MODULE, {replica, Bucket, Node, Type}). + +-doc """ +Same as: + +``` +add_replica(Bucket, Node, disc_only_copies). +``` +""". +-spec add_replica(Bucket, Node) -> ok | {error, Reason} when + Bucket :: atom(), + Node :: atom(), + Reason :: term(). + +add_replica(Bucket, Node) -> + gen_server:call(?MODULE, {replica, Bucket, Node, disc_only_copies}). + -doc """ Same as @@ -184,6 +239,28 @@ add replicas of it calling the `add_replica/3` function. create(Bucket, Nodes, Type) -> gen_server:call(?MODULE, {create, Bucket, Nodes, Type}). +-doc """ +Delete a bucket replica. + +Spec: + +``` +-spec delete_replica(Bucket, Node) -> ok | {error, Reason} when + Bucket :: atom(), + Node :: atom(), + Reason :: term(). +``` + +Delete the `Bucket` replica from the given `Node`. +""". +-spec delete_replica(Bucket, Node) -> ok | {error, Reason} when + Bucket :: atom(), + Node :: atom(), + Reason :: term(). + +delete_replica(Bucket, Node) -> + gen_server:call(?MODULE, {delete_replica, Bucket, Node}). + -doc """ Same as: @@ -231,6 +308,7 @@ added partition, will increase the bucket size by 2GB. That is, the total size increase of the bucket will be `Num` * 2GB. The created partitions are going to be replicated on the given list of `Nodes`, +with priority given to nodes based on the order of the list. Example: @@ -253,6 +331,31 @@ them on 'lab2@sec' with a total size increase of 4 * 2GB = 8GB. grow(Bucket, Nodes, Num) -> gen_server:call(?MODULE, {grow, Bucket, Nodes, Num}). +-doc """ +Move a bucket replica copy between nodes. + +Spec: + +``` +-spec move(Bucket, Source, Dest) -> ok | {error, Reason} when + Bucket :: atom(), + Source :: atom(), + Dest :: atom(), + Reason :: term(). +``` + +The copy of `Bucket` living on `Source`, will be moved to `Dest` and deleted +from the source node once the operation is completed. +""". +-spec move(Bucket, Source, Dest) -> ok | {error, Reason} when + Bucket :: atom(), + Source :: atom(), + Dest :: atom(), + Reason :: term(). + +move(Bucket, Source, Dest) -> + gen_server:call(?MODULE, {move, Bucket, Source, Dest}). + -doc """ Delete the given `Bucket` and all it's replicas. @@ -540,12 +643,24 @@ handle_call({create, Bucket, Nodes, Type}, _From, State) -> {aborted, Reason} -> {reply, {error, Reason}, State} end; +handle_call({delete_replica, Bucket, Node}, _From, State) -> + case mnesia:del_table_copy(Bucket, Node) of + {atomic, _} -> {reply, ok, State}; + {aborted, Reason} -> {reply, {error, Reason}, State} + end; + handle_call({grow, Bucket, Nodes, Num}, _From, State) -> case grow_bucket(Bucket, Nodes, Num) of ok -> {reply, ok, State}; {error, Reason} -> {reply, {error, Reason}, State} end; +handle_call({move, Bucket, Source, Dest}, _From, State) -> + case mnesia:move_table_copy(Bucket, Source, Dest) of + {atomic, ok} -> {reply, ok, State}; + {aborted, Reason} -> {reply, {error, Reason}, State} + end; + handle_call({remove, Bucket}, _From, State) -> case mnesia:delete_table(Bucket) of {atomic, ok} -> {reply, ok, State}; @@ -558,6 +673,12 @@ handle_call({remove, Bucket, Node}, _From, State) -> {aborted, Reason} -> {reply, {error, Reason}, State} end; +handle_call({replica, Bucket, Node, Type}, _From, State) -> + case mnesia:add_table_copy(Bucket, Node, Type) of + {atomic, _} -> {reply, ok, State}; + {aborted, Reason} -> {reply, {error, Reason}, State} + end; + handle_call({shrink, Bucket, Num}, _From, State) -> case shrink_bucket(Bucket, Num) of ok -> {reply, ok, State};