mnesia_tpcb.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,222 行 · 第 1/3 页

ERL
1,222
字号
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MODULE%%%%   mnesia_tpcb - TPC-B benchmarking of Mnesia%%%% DESCRIPTION%%%%   The metrics used in the TPC-B benchmark are throughput as measured%%   in transactions per second (TPS). The benchmark uses a single,%%   simple update-intensive transaction to load the database system.%%   The single transaction type provides a simple, repeatable%%   unit of work, and is designed to exercise the basic components of%%   a database system.%%%%   The definition of the TPC-B states lots of detailed rules and%%   conditions that must be fullfilled, e.g. how the ACID (atomicity,%%   consistency, isolation and durability) properties are verified,%%   how the random numbers must be distributed, minimum sizes of%%   the different types of records, minimum duration of the benchmark,%%   formulas to calculate prices (dollars per tps), disclosure issues%%   etc. Please, see http://www.tpc.org/ about the nitty gritty details.%%%%   The TPC-B benchmark is stated in terms of a hypothetical bank. The%%   bank has one or more branches. Each branch has multiple tellers. The%%   bank has many customers, each with an account. The database represents%%   the cash position of each entity (branch, teller and account) and a%%   history of recent transactions run by the bank. The transaction%%   represents the work done when a customer makes a deposit or a%%   withdrawal against his account. The transaction is performed by a%%   teller at some branch.%%%%   Each process that performs TPC-B transactions is called a driver.%%   Drivers generates teller_id, account_id and delta amount of%%   money randomly. An account, a teller and a branch are read, their%%   balances are adjusted and a history record is created. The driver%%   measures the time for 3 reads, 3 writes and 1 create.%%%% GETTING STARTED%%%%   Generate tables and run with default configuration:%%%%     mnesia_tpcb:start().%%%%  A little bit more advanced;%%%%     spawn(mnesia_tpcb, start, [[[{n_drivers_per_node, 8}, {stop_after, infinity}]]),%%     mnesia_tpcb:stop().%%%%  Really advanced;%%%%    mnesia_tpcb:init(([{n_branches, 8}, {replica_type, disc_only_copies}]),%%    mnesia_tpcb:run(([{n_drivers_per_node, 8}]),%%    mnesia_tpcb:run(([{n_drivers_per_node, 64}]).%%%% AUTHOR%%%%   Hakan Mattsson, hakan@erix.ericsson.se%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-module(mnesia_tpcb).-author('hakan@erix.ericsson.se').-export([	 config/2,	 count_balance/0,	 driver_init/1,	 init/1,	 reporter_init/2,	 run/1,	 start/0,	 start/1,	 start/2,	 stop/0,	 real_trans/5,	 verify_tabs/0,	 reply_gen_branch/3,	 frag_add_delta/6,	 conflict_test/1,	 dist_test/1,	 replica_test/1,	 sticky_replica_test/1,	 remote_test/1,	 remote_frag2_test/1	]).-define(SECOND, 1000000).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Account record, total size must be at least 100 bytes-define(ACCOUNT_FILLER,	{123456789012345678901234567890123456789012345678901234567890,	 123456789012345678901234567890123456789012345678901234567890,	 123456789012345678901234567890123456789012345678901234}).-record(account,       {	id           = 0, % Unique account id	branch_id    = 0, % Branch where the account is held	balance      = 0, % Account balance	filler       = ?ACCOUNT_FILLER  % Gap filler to ensure size >= 100 bytes       }).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Branch record, total size must be at least 100 bytes-define(BRANCH_FILLER,	{123456789012345678901234567890123456789012345678901234567890,	 123456789012345678901234567890123456789012345678901234567890,	 123456789012345678901234567890123456789012345678901234567890}).-record(branch,       {	id           = 0, % Unique branch id	balance      = 0, % Total balance of whole branch	filler       = ?BRANCH_FILLER  % Gap filler to ensure size >= 100 bytes       }).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Teller record, total size must be at least 100 bytes-define(TELLER_FILLER,	{123456789012345678901234567890123456789012345678901234567890,	 123456789012345678901234567890123456789012345678901234567890,	 1234567890123456789012345678901234567890123456789012345678}).-record(teller,       {	id           = 0, % Unique teller id	branch_id    = 0, % Branch where the teller is located	balance      = 0, % Teller balance	filler       = ?TELLER_FILLER % Gap filler to ensure size >= 100 bytes       }).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% History record, total size must be at least 50 bytes-define(HISTORY_FILLER, 1234567890).-record(history,	{	 history_id  = {0, 0}, % {DriverId, DriverLocalHistoryid}	 time_stamp  = now(), % Time point during active transaction	 branch_id   = 0, % Branch associated with teller	 teller_id   = 0, % Teller invlolved in transaction	 account_id  = 0, % Account updated by transaction	 amount      = 0, % Amount (delta) specified by transaction	 filler      = ?HISTORY_FILLER % Gap filler to ensure size >= 50 bytes       }).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-record(tab_config,	{	  db_nodes = [node()],	  replica_nodes = [node()],	  replica_type = ram_copies,	  use_running_mnesia = false,	  n_fragments = 0,	  n_branches = 1,	  n_tellers_per_branch = 10, % Must be 10	  n_accounts_per_branch = 100000, % Must be 100000	  branch_filler = ?BRANCH_FILLER,	  account_filler = ?ACCOUNT_FILLER,	  teller_filler = ?TELLER_FILLER	 }).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-record(run_config,	{	  driver_nodes = [node()],	  n_drivers_per_node = 1,	  use_running_mnesia = false,	  stop_after = timer:minutes(15), % Minimum 15 min	  report_interval = timer:minutes(1),	  use_sticky_locks = false,	  spawn_near_branch = false,	  activity_type = transaction,	  reuse_history_id = false	 }).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-record(time,	{	  n_trans = 0,	  min_n = 0,	  max_n = 0,	  acc_time = 0,	  max_time = 0	 }).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-record(driver_state,	{	  driver_id,	  driver_node,	  seed,	  local_branches,	  n_local_branches,	  tab_config,	  run_config,	  history_id,	  time = #time{},	  acc_time = #time{},	  reuse_history_id	 }).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-record(reporter_state,	{	  driver_pids,	  starter_pid,	  n_iters = 0,	  prev_tps = 0,	  curr = #time{},	  acc = #time{},	  init_micros,	  prev_micros,	  run_config	 }).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% One driver on this node, table not replicatedconfig(frag_test, ReplicaType) ->    Nodes = [node() | nodes()],    [     {n_branches, length(Nodes)},     {n_fragments, length(Nodes)},     {replica_nodes, 1},     {db_nodes, Nodes},     {driver_nodes, Nodes},     {n_accounts_per_branch, 100},     {replica_type, ReplicaType},     {stop_after, timer:minutes(1)},     {report_interval, timer:seconds(10)},     {reuse_history_id, true}    ];%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% One driver on this node, table replicated to two nodes.config(frag2_test, ReplicaType) ->    Nodes = [node() | nodes()],    [     {n_branches, length(Nodes)},     {n_fragments, length(Nodes)},     {replica_nodes, 2},     {db_nodes, Nodes},     {driver_nodes, Nodes},     {n_accounts_per_branch, 100},     {replica_type, ReplicaType},     {stop_after, timer:minutes(1)},     {report_interval, timer:seconds(10)},     {reuse_history_id, true}    ];%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% One driver on this node, table replicated to all nodes.config(replica_test, ReplicaType) ->    Nodes = [node() | nodes()],    [     {db_nodes, Nodes},     {driver_nodes, [node()]},     {replica_nodes, Nodes},     {n_accounts_per_branch, 100},     {replica_type, ReplicaType},     {stop_after, timer:minutes(1)},     {report_interval, timer:seconds(10)},     {reuse_history_id, true}    ];%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% One driver on this node, table replicated to all nodes.config(sticky_replica_test, ReplicaType) ->    Nodes = [node()|nodes()],    [     {db_nodes, Nodes},     {driver_nodes, [node()]},     {replica_nodes, Nodes},     {n_accounts_per_branch, 100},     {replica_type, ReplicaType},     {use_sticky_locks, true},     {stop_after, timer:minutes(1)},     {report_interval, timer:seconds(10)},     {reuse_history_id, true}    ];%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Ten drivers per node, tables replicated to all nodes, lots of branchesconfig(dist_test, ReplicaType) ->    Nodes = [node()|nodes()],    [     {db_nodes, Nodes},     {driver_nodes, Nodes},     {replica_nodes, Nodes},     {n_drivers_per_node, 10},     {n_branches, 10 * length(Nodes) * 100},     {n_accounts_per_branch, 10},     {replica_type, ReplicaType},     {stop_after, timer:minutes(1)},     {report_interval, timer:seconds(10)},     {reuse_history_id, true}    ];%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Ten drivers per node, tables replicated to all nodes, single branchconfig(conflict_test, ReplicaType) ->    Nodes = [node()|nodes()],    [     {db_nodes, Nodes},     {driver_nodes, Nodes},     {replica_nodes, Nodes},     {n_drivers_per_node, 10},     {n_branches, 1},     {n_accounts_per_branch, 10},     {replica_type, ReplicaType},     {stop_after, timer:minutes(1)},     {report_interval, timer:seconds(10)},     {reuse_history_id, true}    ];%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% One driver on this node, table replicated to all other nodes.config(remote_test, ReplicaType) ->    Remote = nodes(),    Local = node(),    Nodes = [Local | Remote],    [     {db_nodes, Nodes},     {driver_nodes, [Local]},     {replica_nodes, Remote},     {n_accounts_per_branch, 100},     {replica_type, ReplicaType},     {stop_after, timer:minutes(1)},     {report_interval, timer:seconds(10)},     {reuse_history_id, true}    ];%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% One driver on this node, table replicated to two other nodes.config(remote_frag2_test, ReplicaType) ->    Remote = nodes(),    Local = node(),    Nodes = [Local | Remote],    [     {n_branches, length(Remote)},     {n_fragments, length(Remote)},     {replica_nodes, 2},     {db_nodes, Nodes},     {driver_nodes, [Local]},     {n_accounts_per_branch, 100},     {replica_type, ReplicaType},     {stop_after, timer:minutes(1)},     {report_interval, timer:seconds(10)},     {reuse_history_id, true}    ].%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%start(What, ReplicaType) ->    spawn_link(?MODULE, start, [config(What, ReplicaType)]).replica_test(ReplicaType) ->    start(replica_test, ReplicaType).sticky_replica_test(ReplicaType) ->    start(sticky_replica_test, ReplicaType).dist_test(ReplicaType) ->    start(dist_test, ReplicaType).conflict_test(ReplicaType) ->    start(conflict_test, ReplicaType).remote_test(ReplicaType) ->    start(remote_test, ReplicaType).remote_frag2_test(ReplicaType) ->    start(remote_frag2_test, ReplicaType).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Args is a list of {Key, Val} tuples where Key is a field name%% in either the record tab_config or run_config. Unknown keys are ignored.start() ->    start([]).start(Args) ->    init(Args),    run(Args).list2rec(List, Fields, DefaultTuple) ->

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?