Permalink
Browse files

Add a background lock and task manager module to riak core.

* The goal is to allow riak sub-systems to coordinate use of shared resources,
* e.g. protect from concurrent vnode folds on the same partition.
* Locks and tokens have a settable maximum concurrency limit.
* "Taken" locks and tokens are tracked in an ETS table.
* max_concurrency is returned when the set limits are reached.
* Processes that take locks are monitored.
* Locks are released when the taking processes terminate.
* Tokens are refreshed at a specified periodic rate.
* Token processes are not monitored because tokens never "release".
* A table manager is introduced to add persistence across process crashes,
* and to allow proper table transfer to occur without losing the table.
* An EQC test exercises the majority of the API. see test/bg_manager_eqc.erl
* See the original PR for background manager here: #364
  • Loading branch information...
1 parent d7139c1 commit d8048dd0b4e453a476a7d4f9103e14fdd1a8c802 @buddhisthead buddhisthead committed Oct 4, 2013
Showing with 2,631 additions and 3 deletions.
  1. +88 −0 include/riak_core_bg_manager.hrl
  2. +1,142 −0 src/riak_core_bg_manager.erl
  3. +15 −3 src/riak_core_sup.erl
  4. +187 −0 src/riak_core_table_manager.erl
  5. +1,003 −0 test/bg_manager_eqc.erl
  6. +196 −0 test/bg_manager_tests.erl
@@ -0,0 +1,88 @@
+%% -------------------------------------------------------------------
+%%
+%% Copyright (c) 2013 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.
+%%
+%% NOTES:
+%% The background manager allows tokens and locks to be "acquired" by
+%% competing processes in a way that limits the total load on the cluster.
+%%
+%% The model is different than your typical semaphore. Here, we are
+%% interested in coordinating background jobs that start, run, and die.
+%%
+%%
+%% The term "given" is a general version of "held", "acquired", or
+%% "allocated" for both locks and tokens. Held doesn't make sense for
+%% tokens since they aren't held. So, "given" applies to both locks
+%% and tokens, but you can think "held" for locks if that's more fun.
+%%
+%% Resources are defined by their "names", which is the same as "type"
+%% or "kind". A lock name might be the atom 'aae_hashtree_lock' or the
+%% tuple '{my_ultimate_lock, 42}'.
+%%
+%% Usage:
+%% 1. register your lock/token and set it's max concurrency/rate.
+%% 2. "get" a lock/token by it's resource type/name
+%% 3. do stuff
+%% 4. let your process die, which gives back a lock.
+%% -------------------------------------------------------------------
+-type bg_lock() :: any().
+-type bg_token() :: any().
+-type bg_resource() :: bg_token() | bg_lock().
+-type bg_resource_type() :: lock | token.
+
+-type bg_meta() :: {atom(), any()}. %% meta data to associate with a lock/token
+-type bg_period() :: pos_integer(). %% token refill period in milliseconds
+-type bg_count() :: pos_integer(). %% token refill tokens to count at each refill period
+-type bg_rate() :: undefined | {bg_period(), bg_count()}. %% token refill rate
+-type bg_concurrency_limit() :: non_neg_integer() | infinity. %% max lock concurrency allowed
+-type bg_state() :: given | blocked | failed. %% state of an instance of a resource.
+
+%% Results of a "ps" of live given or blocked locks/tokens
+-record(bg_stat_live,
+ {
+ resource :: bg_resource(), %% resource name, e.g. 'aae_hashtree_lock'
+ type :: bg_resource_type(), %% resource type, e.g. 'lock'
+ consumer :: pid(), %% process asking for token
+ meta :: [bg_meta()], %% associated meta data
+ state :: bg_state() %% result of last request, e.g. 'given'
+ }).
+-type bg_stat_live() :: #bg_stat_live{}.
+
+%% Results of a "head" or "tail", per resource. Historical query result.
+-record(bg_stat_hist,
+ {
+ type :: undefined | bg_resource_type(), %% undefined only on default
+ limit :: non_neg_integer(), %% maximum available, defined by token rate during interval
+ refills :: non_neg_integer(), %% number of times a token was refilled during interval. 0 if lock
+ given :: non_neg_integer(), %% number of times this resource was handed out within interval
+ blocked :: non_neg_integer() %% number of blocked processes waiting for a token
+ }).
+-type bg_stat_hist() :: #bg_stat_hist{}.
+-define(BG_DEFAULT_STAT_HIST,
+ #bg_stat_hist{type=undefined, limit=undefined, refills=0, given=0, blocked=0}).
+
+-define(BG_DEFAULT_WINDOW_INTERVAL, 60*1000). %% in milliseconds
+-define(BG_DEFAULT_OUTPUT_SAMPLES, 20). %% default number of sample windows displayed
+-define(BG_DEFAULT_KEPT_SAMPLES, 10000). %% number of history samples to keep
+
+-define(BG_INFO_ETS_TABLE, background_mgr_info_table). %% name of private lock/token manager info ETS table
+-define(BG_INFO_ETS_OPTS, [private, set]). %% creation time properties of info ETS table
+
+-define(BG_ENTRY_ETS_TABLE, background_mgr_entry_table). %% name of private lock/token manager entry ETS table
+-define(BG_ENTRY_ETS_OPTS, [private, bag]). %% creation time properties of entry ETS table
+
+
Oops, something went wrong.

0 comments on commit d8048dd

Please sign in to comment.