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 + -
显示快捷键?