Ring Resize Operations

Hint

Additional information can be found in the official documentation.

Riak core has a method for resizing the ring. This allows a installation that was started with a certain ring_size (say 64) to either grow or shrink.

As a word of warning ahead of time, this operation is risky, it requires large part of the data to be re-written and deleted so it is a risky operation.

The basic procedure is performed in a few steps, some of which are fully handled by riak_core others need to be implemented.

Preparation

The first part is handled by riak_core itself, when a resize request is given riak_core will compute a second ring, reflecting the new size and work out what vnode goes to which node.

Handoffs

Next up are the handoffs, riak_core will use handoffs to move data from the old vnode to the new one. The handoffs will potentially be performed multiple times using filters to shard the data over new vnodes.

For this to work the handle_command function needs to implement a case that accepts a ?FOLD_REQ. This case needs to fold over all bucket and key combinations!

The fold function that is passed in needs to be called with 3 arguments:

  1. The bucket and key, the formate here is important! {Bucket, Key}
  2. The object.
  3. The accumulator.

Additional functions

There need to be some additional functions implemented:

nval_map(Ring) This function should return a list of buckets and their nval if it differs from the standard. The following is a sample implementation taken from riak_kv. It works well if either there are no bucket specific n-values or the riak_core_bucket module is used to manage them.

nval_map(Ring) ->
   riak_core_bucket:bucket_nval_map(Ring).

object_info({Bucket, Key} This function computes the hash for a bucket / key combination to determine it’s new placing. The following is sample implementation, taken from riak_kv. It works for most cases where no custom hashing or bucket naming is used.

object_info({Bucket, Key}=BKey) ->
    Hash = riak_core_util:chash_key(BKey),
    {Bucket, Hash}.

request_hash(Request) This function is called for every incoming request for a vnode that is handing off data as part of a resize operation. For operations that should be forwarded it should return the hash as returned by riak_core_util:chash_key and undefined for the rest. The goal is to determine what vnode it should be forwarded to (if any). This forwarding happens in addition to executing the query locally! The normal approach is to only forward modifying operations such as writes or deletes and to return undefined for all others.