/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * This file contains original code and/or modifications of original code. * Any modifications made by VoltDB Inc. are licensed under the following * terms and conditions: * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /* Copyright (C) 2008 * Evan Jones * Massachusetts Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ package com; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.Iterator; import org.voltdb.VoltTable; import org.voltdb.VoltType; import org.voltdb.types.TimestampType; import org.voltdb.client.Client; import org.voltdb.client.ClientResponse; import org.voltdb.client.ProcCallException; import org.voltdb.client.NoConnectionsException; import org.voltdb.client.ProcedureCallback; import org.voltdb.client.exampleutils.AppHelper; import org.voltdb.client.exampleutils.ClientConnection; import java.util.concurrent.Semaphore; import org.voltcore.utils.Pair; /** TPC-C database loader. Note: The methods order id parameters from "top level" to "low level" parameters. However, the insert stored procedures use the defined TPC-C table order, which goes from "low level" to "top level" (except in the case of order line, which is inconsistent). As as example, this class uses (o_w_id, o_d_id, o_id), whereas the order table is defined as (o_id, o_d_id, o_w_id). */ public class MyLoader { private AppHelper m_helpah; private final ClientConnection m_voltClient; /** * Number of threads to create to do the loading. */ private final LoadThread m_loadThreads[]; private final int m_warehouses; private static final VoltTable.ColumnInfo customerTableColumnInfo[] = new VoltTable.ColumnInfo[] { new VoltTable.ColumnInfo("C_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("C_D_ID", VoltType.TINYINT), new VoltTable.ColumnInfo("C_W_ID", VoltType.SMALLINT), new VoltTable.ColumnInfo("C_FIRST", VoltType.STRING), new VoltTable.ColumnInfo("C_LAST", VoltType.STRING) }; private static final LinkedList<VoltTable> customerNamesTables = new LinkedList<VoltTable>(); private static final Semaphore m_finishedLoadThreads = new Semaphore(0); public MyLoader(String args[], ClientConnection voltClient) { m_helpah = new AppHelper(MyTPCC.class.getCanonicalName()); m_helpah.add("duration", "run_duration_in_seconds", "Benchmark duration, in seconds.", 180); m_helpah.add("warehouses", "number_of_warehouses", "Number of warehouses", 256); m_helpah.add("scalefactor", "scale_factor", "Reduces per-warehouse data by warehouses/scalefactor", 22.0); m_helpah.add("skew-factor", "skew_factor", "Skew factor", 0.0); m_helpah.add("load-threads", "number_of_load_threads", "Number of load threads", 4); m_helpah.add("ratelimit", "rate_limit", "Rate limit to start from (tps)", 200000); m_helpah.add("displayinterval", "display_interval_in_seconds", "Interval for performance feedback, in seconds.", 10); m_helpah.add("servers", "comma_separated_server_list", "List of VoltDB servers to connect to.", "localhost"); m_helpah.setArguments(args); initTableNames(); int warehouses = m_helpah.intValue("warehouses"); double scaleFactor = m_helpah.doubleValue("scalefactor"); int loadThreads = m_helpah.intValue("load-threads"); if (loadThreads > warehouses) { System.out.println("Specified number of load threads exceeds number of warehouses. Setting former equal to latter."); loadThreads = warehouses; } m_warehouses = warehouses; m_loadThreads = new LoadThread[loadThreads]; for (int ii = 0; ii < loadThreads; ii++) { ScaleParameters parameters = ScaleParameters.makeWithScaleFactor(warehouses, scaleFactor); assert parameters != null; RandomGenerator generator = new RandomGenerator.Implementation(0); TimestampType generationDateTime = new TimestampType(); RandomGenerator.NURandC loadC = RandomGenerator.NURandC.makeForLoad(generator); generator.setC(loadC); m_loadThreads[ii] = new LoadThread( generator, generationDateTime, parameters, ii); } m_voltClient = voltClient; } private String[] table_names = new String[8]; private final static int IDX_WAREHOUSES = 0; private final static int IDX_DISTRICTS = 1; private final static int IDX_CUSTOMERS = 2; private final static int IDX_STOCKS = 3; private final static int IDX_ORDERS = 4; private final static int IDX_NEWORDERS = 5; private final static int IDX_ORDERLINES = 6; private final static int IDX_HISTORIES = 7; private void initTableNames() { table_names[IDX_WAREHOUSES] = "warehouse"; table_names[IDX_DISTRICTS] = "district"; table_names[IDX_CUSTOMERS] = "customer"; table_names[IDX_STOCKS] = "stock"; table_names[IDX_ORDERS] = "orders"; table_names[IDX_NEWORDERS] = "new_order"; table_names[IDX_ORDERLINES] = "order_line"; table_names[IDX_HISTORIES] = "history"; } /** * Hint used when constructing the Client to control the size of buffers allocated for message * serialization * @return */ protected int getExpectedOutgoingMessageSize() { return 10485760; } private void rethrowExceptionLoad(String procedureName, Object... parameters) { try { VoltTable ret[] = m_voltClient.execute(procedureName, parameters).getResults(); assert ret.length == 0; } catch (ProcCallException e) { e.printStackTrace(); System.exit(-1); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } } class LoadThread extends Thread { private final RandomGenerator m_generator; private final TimestampType m_generationDateTime; private final ScaleParameters m_parameters; /** table data FOR CURRENT WAREHOUSE (LoadWarehouse is partitioned on WID).*/ private final VoltTable[] data_tables = new VoltTable[8]; // non replicated tables private volatile boolean m_doMakeReplicated = false; public LoadThread( RandomGenerator generator, TimestampType generationDateTime, ScaleParameters parameters, int index) { super("Load Thread " + index); m_generator = generator; this.m_generationDateTime = generationDateTime; this.m_parameters = parameters; } @Override public void run() { Integer warehouseId = null; while ((warehouseId = availableWarehouseIds.poll()) != null) { System.err.println("Loading warehouse " + warehouseId); makeStock(warehouseId); // STOCK is made separately to reduce memory consumption createDataTables(); makeWarehouse(warehouseId); for (int i = 0; i < data_tables.length; ++i) data_tables[i] = null; } if (m_doMakeReplicated) { try { m_finishedLoadThreads.acquire(m_loadThreads.length - 1); } catch (InterruptedException e) { throw new RuntimeException(e); } makeReplicated(); m_doMakeReplicated = false; } else { m_finishedLoadThreads.release(); } } public void start(boolean doMakeReplicated) { m_doMakeReplicated = doMakeReplicated; super.start(); } private double makeTax() { return m_generator.fixedPoint(Constants.TAX_DECIMALS, Constants.MIN_TAX, Constants.MAX_TAX); } private String makeZip() { int length = Constants.ZIP_LENGTH - Constants.ZIP_SUFFIX.length(); return m_generator.nstring(length, length) + Constants.ZIP_SUFFIX; } private HashSet<Integer> selectUniqueIds(int numUnique, int minimum, int maximum) { HashSet<Integer> rows = new HashSet<Integer>(numUnique * 2); for (int i = 0; i < numUnique; ++i) { int index; do { index = m_generator.number(minimum, maximum); } while (rows.contains(index)); assert !rows.contains(index); rows.add(index); } assert rows.size() == numUnique; return rows; } /** @returns a string with ORIGINAL_STRING at a random position. */ private String fillOriginal(String data) { int originalLength = Constants.ORIGINAL_STRING.length(); int position = m_generator.number(0, data.length() - originalLength); String out = data.substring(0, position) + Constants.ORIGINAL_STRING + data.substring(position + originalLength); assert out.length() == data.length(); return out; } /** Inserts a new item with id, generated according to the TPC-C specification 4.3.3.1. * @param items * @param id * @param original */ public void generateItem(VoltTable items, long id, boolean original) { long i_id = id; long i_im_id = m_generator.number(Constants.MIN_IM, Constants.MAX_IM); String i_name = m_generator.astring(Constants.MIN_I_NAME, Constants.MAX_I_NAME); double i_price = m_generator.fixedPoint( Constants.MONEY_DECIMALS, Constants.MIN_PRICE, Constants.MAX_PRICE); String i_data = m_generator.astring(Constants.MIN_I_DATA, Constants.MAX_I_DATA); if (original) { i_data = fillOriginal(i_data); } items.addRow(i_id, i_im_id, i_name, i_price, i_data); } public void generateWarehouse(long w_id) { double w_tax = makeTax(); double w_ytd = Constants.INITIAL_W_YTD; ArrayList<Object> insertParameters = new ArrayList<Object>(); insertParameters.add(w_id); addAddress(insertParameters); insertParameters.addAll(Arrays.asList(w_tax, w_ytd)); data_tables[IDX_WAREHOUSES].addRow(insertParameters.toArray()); } public void generateDistrict(long d_w_id, long d_id) { double d_tax = makeTax(); double d_ytd = Constants.INITIAL_D_YTD; long d_next_o_id = m_parameters.customersPerDistrict + 1; ArrayList<Object> insertParameters = new ArrayList<Object>(Arrays.asList(d_id, d_w_id)); addAddress(insertParameters); insertParameters.addAll(Arrays.asList(new Object[]{d_tax, d_ytd, d_next_o_id})); data_tables[IDX_DISTRICTS].addRow(insertParameters.toArray()); } private final Object[] container_customer = new Object[6 + 5 + 10]; public void generateCustomer(long c_w_id, long c_d_id, long c_id, boolean badCredit, boolean doesReplicateName) { String c_first = m_generator.astring(Constants.MIN_FIRST, Constants.MAX_FIRST); String c_middle = Constants.MIDDLE; assert 1 <= c_id && c_id <= Constants.CUSTOMERS_PER_DISTRICT; String c_last; if (c_id <= 1000) { c_last = m_generator.makeLastName((int) c_id-1); } else { c_last = m_generator.makeRandomLastName(m_parameters.customersPerDistrict); } String c_phone = m_generator.nstring(Constants.PHONE, Constants.PHONE); TimestampType c_since = m_generationDateTime; String c_credit = badCredit ? Constants.BAD_CREDIT : Constants.GOOD_CREDIT; double c_credit_lim = Constants.INITIAL_CREDIT_LIM; double c_discount = m_generator.fixedPoint( Constants.DISCOUNT_DECIMALS, Constants.MIN_DISCOUNT, Constants.MAX_DISCOUNT); double c_balance = Constants.INITIAL_BALANCE; double c_ytd_payment = Constants.INITIAL_YTD_PAYMENT; long c_payment_cnt = Constants.INITIAL_PAYMENT_CNT; long c_delivery_cnt = Constants.INITIAL_DELIVERY_CNT; String c_data = m_generator.astring(Constants.MIN_C_DATA, Constants.MAX_C_DATA); int ind = 0; container_customer[ind++] = c_id; container_customer[ind++] = c_d_id; container_customer[ind++] = c_w_id; container_customer[ind++] = c_first; container_customer[ind++] = c_middle; container_customer[ind++] = c_last; String street1 = m_generator.astring(Constants.MIN_STREET, Constants.MAX_STREET); String street2 = m_generator.astring(Constants.MIN_STREET, Constants.MAX_STREET); String city = m_generator.astring(Constants.MIN_CITY, Constants.MAX_CITY); String state = m_generator.astring(Constants.STATE, Constants.STATE); String zip = makeZip(); container_customer[ind++] = street1; container_customer[ind++] = street2; container_customer[ind++] = city; container_customer[ind++] = state; container_customer[ind++] = zip; container_customer[ind++] = c_phone; container_customer[ind++] = c_since; container_customer[ind++] = c_credit; container_customer[ind++] = c_credit_lim; container_customer[ind++] = c_discount; container_customer[ind++] = c_balance; container_customer[ind++] = c_ytd_payment; container_customer[ind++] = c_payment_cnt; container_customer[ind++] = c_delivery_cnt; container_customer[ind++] = c_data; data_tables[IDX_CUSTOMERS].addRow(container_customer); if (doesReplicateName) { //replicate name and id to every site synchronized (customerNamesTables) { VoltTable customerNames = customerNamesTables.peekFirst(); if (customerNames == null || customerNames.getRowCount() > 32760) { customerNames = new VoltTable(customerTableColumnInfo); customerNamesTables.push(customerNames); } customerNames.addRow(c_id, c_d_id, c_w_id, c_first, c_last); } } } /** Appends the name and address fields to insertParameters. Used by both generateWarehouse and generateDistrict. */ private void addAddress(ArrayList<Object> insertParameters) { String name = m_generator.astring(Constants.MIN_NAME, Constants.MAX_NAME); insertParameters.add(name); addStreetAddress(insertParameters); } /** Appends the street address fields to insertParameters. Used for warehouses, districts and customers. */ private void addStreetAddress(ArrayList<Object> insertParameters) { String street1 = m_generator.astring(Constants.MIN_STREET, Constants.MAX_STREET); String street2 = m_generator.astring(Constants.MIN_STREET, Constants.MAX_STREET); String city = m_generator.astring(Constants.MIN_CITY, Constants.MAX_CITY); String state = m_generator.astring(Constants.STATE, Constants.STATE); String zip = makeZip(); insertParameters.addAll(Arrays.asList(street1, street2, city, state, zip)); } private final Object[] container_stock = new Object[3 + Constants.DISTRICTS_PER_WAREHOUSE + 4]; public void generateStock(long s_w_id, long s_i_id, boolean original) { long s_quantity = m_generator.number(Constants.MIN_QUANTITY, Constants.MAX_QUANTITY); long s_ytd = 0; long s_order_cnt = 0; long s_remote_cnt = 0; String s_data = m_generator.astring(Constants.MIN_I_DATA, Constants.MAX_I_DATA); if (original) { s_data = fillOriginal(s_data); } int ind = 0; container_stock[ind++] = s_i_id; container_stock[ind++] = s_w_id; container_stock[ind++] = s_quantity; for (int i = 0; i < Constants.DISTRICTS_PER_WAREHOUSE; ++i) { String s_dist_x = m_generator.astring(Constants.DIST, Constants.DIST); container_stock[ind++] = s_dist_x; } container_stock[ind++] = s_ytd; container_stock[ind++] = s_order_cnt; container_stock[ind++] = s_remote_cnt; container_stock[ind++] = s_data; data_tables[IDX_STOCKS].addRow(container_stock); } /* returns the generated o_ol_cnt value. */ public long generateOrder(long o_w_id, long o_d_id, long o_id, long o_c_id, boolean newOrder) { TimestampType o_entry_d = m_generationDateTime; long o_carrier_id; if (!newOrder) { o_carrier_id = m_generator.number(Constants.MIN_CARRIER_ID, Constants.MAX_CARRIER_ID); } else { o_carrier_id = Constants.NULL_CARRIER_ID; } long o_ol_cnt = m_generator.number(Constants.MIN_OL_CNT, Constants.MAX_OL_CNT); long o_all_local = Constants.INITIAL_ALL_LOCAL; data_tables[IDX_ORDERS].addRow(o_id, o_d_id, o_w_id, o_c_id, o_entry_d, o_carrier_id, o_ol_cnt, o_all_local); return o_ol_cnt; } public void generateOrderLine(long ol_w_id, long ol_d_id, long ol_o_id, long ol_number, boolean newOrder) { long ol_i_id = m_generator.number(1, m_parameters.items); long ol_supply_w_id = ol_w_id; TimestampType ol_delivery_d = m_generationDateTime; long ol_quantity = Constants.INITIAL_QUANTITY; double ol_amount; if (!newOrder) { ol_amount = 0.00; } else { ol_amount = m_generator.fixedPoint(Constants.MONEY_DECIMALS, Constants.MIN_AMOUNT, Constants.MAX_PRICE * Constants.MAX_OL_QUANTITY); ol_delivery_d = null; } String ol_dist_info = m_generator.astring(Constants.DIST, Constants.DIST); data_tables[IDX_ORDERLINES].addRow(ol_o_id, ol_d_id, ol_w_id, ol_number, ol_i_id, ol_supply_w_id, ol_delivery_d, ol_quantity, ol_amount, ol_dist_info); } //private long max_hid = 0; public void generateHistory(long h_c_w_id, long h_c_d_id, long h_c_id) { long h_w_id = h_c_w_id; long h_d_id = h_c_d_id; TimestampType h_date = m_generationDateTime; double h_amount = Constants.INITIAL_AMOUNT; String h_data = m_generator.astring(Constants.MIN_DATA, Constants.MAX_DATA); data_tables[IDX_HISTORIES].addRow(h_c_id, h_c_d_id, h_c_w_id, h_d_id, h_w_id, h_date, h_amount, h_data); } /** STOCK is made in different method to reduce memory consumption. */ public void makeStock(int w_id) { // Select 10% of the stock to be marked "original" final int BATCH = 5; final int BATCH_SIZE = (m_parameters.items / BATCH); data_tables[IDX_STOCKS] = new VoltTable( new VoltTable.ColumnInfo("S_I_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("S_W_ID", VoltType.SMALLINT), new VoltTable.ColumnInfo("S_QUANTITY", VoltType.INTEGER), new VoltTable.ColumnInfo("S_DIST_01", VoltType.STRING), new VoltTable.ColumnInfo("S_DIST_02", VoltType.STRING), new VoltTable.ColumnInfo("S_DIST_03", VoltType.STRING), new VoltTable.ColumnInfo("S_DIST_04", VoltType.STRING), new VoltTable.ColumnInfo("S_DIST_05", VoltType.STRING), new VoltTable.ColumnInfo("S_DIST_06", VoltType.STRING), new VoltTable.ColumnInfo("S_DIST_07", VoltType.STRING), new VoltTable.ColumnInfo("S_DIST_08", VoltType.STRING), new VoltTable.ColumnInfo("S_DIST_09", VoltType.STRING), new VoltTable.ColumnInfo("S_DIST_10", VoltType.STRING), new VoltTable.ColumnInfo("S_YTD", VoltType.INTEGER), new VoltTable.ColumnInfo("S_ORDER_CNT", VoltType.INTEGER), new VoltTable.ColumnInfo("S_REMOTE_CNT", VoltType.INTEGER), new VoltTable.ColumnInfo("S_DATA", VoltType.STRING) ); //t.ensureRowCapacity(parameters.items / BATCH); //t.ensureStringCapacity(parameters.items * (32 * 10 + 64) / BATCH); HashSet<Integer> selectedRows = selectUniqueIds(m_parameters.items/10, 1, m_parameters.items); for (int i_id = 1; i_id <= m_parameters.items; ++i_id) { boolean original = selectedRows.contains(i_id); generateStock(w_id, i_id, original); if (i_id % BATCH_SIZE == 0) { commitDataTables(w_id); //System.err.printf("%d/%d\n", i_id, m_parameters.items); } } if (data_tables[IDX_STOCKS].getRowCount() != 0) { commitDataTables(w_id); } data_tables[IDX_STOCKS] = null; } // TODO(evanj): The C++ version has tests for this code that could be ported over, but it would // need a fair bit of hacking in the unit test to make them work, since it requires storing all // the inserted tuples. public void makeWarehouse(long w_id) { generateWarehouse(w_id); for (int d_id = 1; d_id <= m_parameters.districtsPerWarehouse; ++d_id) { //System.err.printf("Beginning District: %d\n", d_id); generateDistrict(w_id, d_id); // Select 10% of the customers to have bad credit HashSet<Integer> selectedRows = selectUniqueIds(m_parameters.customersPerDistrict/10, 1, m_parameters.customersPerDistrict); // long[] c_ids = new long[customersPerDistrict]; for (int c_id = 1; c_id <= m_parameters.customersPerDistrict; ++c_id) { boolean badCredit = selectedRows.contains(c_id); generateCustomer(w_id, d_id, c_id, badCredit, true); generateHistory(w_id, d_id, c_id); } // TPC-C 4.3.3.1. says that o_c_id should be a permutation of [1, 3000]. But since it // is a c_id field, it seems to make sense to have it be a permutation of the // customers. For the "real" thing this will be equivalent int[] cIdPermutation = new int[m_parameters.customersPerDistrict]; for (int i = 0; i < m_parameters.customersPerDistrict; ++i) { cIdPermutation[i] = i+1; } assert cIdPermutation[0] == 1; assert cIdPermutation[m_parameters.customersPerDistrict-1] == m_parameters.customersPerDistrict; Collections.shuffle(Arrays.asList(cIdPermutation)); for (int o_id = 1; o_id <= m_parameters.customersPerDistrict; ++o_id) { // The last newOrdersPerDistrict are new orders boolean newOrder = m_parameters.customersPerDistrict - m_parameters.newOrdersPerDistrict < o_id; long o_ol_cnt = generateOrder(w_id, d_id, o_id, cIdPermutation[o_id-1], newOrder); // Generate each OrderLine for the order for (int ol_number = 1; ol_number <= o_ol_cnt; ++ol_number) { generateOrderLine(w_id, d_id, o_id, ol_number, newOrder); } if (newOrder) { // This is a new order: make one for it data_tables[IDX_NEWORDERS].addRow((long) o_id, (long) d_id, w_id); } } commitDataTables(w_id); // flushout current data to avoid outofmemory } } /** generate replicated tables, ITEM and CUSTOMER_NAME. */ public void makeReplicated() { // create ITEMS here to reduce memory consumption VoltTable items = new VoltTable( new VoltTable.ColumnInfo("I_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("I_IM_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("I_NAME", VoltType.STRING), new VoltTable.ColumnInfo("I_PRICE", VoltType.FLOAT), new VoltTable.ColumnInfo("I_DATA", VoltType.STRING) ); //items.ensureRowCapacity(parameters.items); //items.ensureStringCapacity(parameters.items * 96); // Select 10% of the rows to be marked "original" HashSet<Integer> originalRows = selectUniqueIds(m_parameters.items/10, 1, m_parameters.items); for (int i = 1; i <= m_parameters.items; ++i) { // if we're on a 10% boundary, print out some nice status info //if (i % (m_parameters.items / 10) == 0) // System.err.printf(" %d%%\n", (i * 100) / m_parameters.items); boolean original = originalRows.contains(i); generateItem(items, i, original); } if (m_voltClient != null) { // XXX final int numPermits = 48; final Semaphore maxOutstandingInvocations = new Semaphore(numPermits); final int totalInvocations = customerNamesTables.size() * m_parameters.warehouses; final ProcedureCallback callback = new ProcedureCallback() { private int invocationsCompleted = 0; private double lastPercentCompleted = 0.0; @Override public synchronized void clientCallback(ClientResponse clientResponse) { if (clientResponse.getStatus() != ClientResponse.SUCCESS){ System.err.println(clientResponse.getStatusString()); System.exit(-1); } invocationsCompleted++; final double percentCompleted = invocationsCompleted / (double)totalInvocations; if (percentCompleted > lastPercentCompleted + .1) { lastPercentCompleted = percentCompleted; System.err.println("Finished " + invocationsCompleted + "/" + totalInvocations + " replicated load work"); } maxOutstandingInvocations.release(); } }; LinkedList<Pair<Integer, LinkedList<VoltTable>>> replicatedLoadWork = new LinkedList<Pair<Integer, LinkedList<VoltTable>>>(); int totalLoadWorkGenerated = 0; for (int w_id = 1; w_id <= m_parameters.warehouses; ++w_id) { replicatedLoadWork.add( new Pair<Integer, LinkedList<VoltTable>>( w_id, new LinkedList<VoltTable>(customerNamesTables), false)); totalLoadWorkGenerated += customerNamesTables.size(); } Collections.shuffle(replicatedLoadWork); System.err.println("Total load work generated is " + totalLoadWorkGenerated); /* * Only supply item table the first time. */ for (Pair<Integer, LinkedList<VoltTable>> p : replicatedLoadWork) { try { VoltTable table = p.getSecond().pop(); boolean queued = false; while (!queued) { queued = m_voltClient.executeAsync(callback, Constants.LOAD_WAREHOUSE_REPLICATED, (short)p.getFirst().intValue(), items, table); m_voltClient.backpressureBarrier(); } } catch (Exception e) { e.printStackTrace(); System.exit(-1); } } while (!replicatedLoadWork.isEmpty()) { Iterator<Pair<Integer, LinkedList<VoltTable>>> iter = replicatedLoadWork.iterator(); while (iter.hasNext()) { Pair<Integer, LinkedList<VoltTable>> p = iter.next(); if (p.getSecond().peek() == null) { iter.remove(); continue; } try { maxOutstandingInvocations.acquire(); VoltTable table = p.getSecond().pop(); boolean queued = false; while (!queued) { queued = m_voltClient.executeAsync(callback, Constants.LOAD_WAREHOUSE_REPLICATED, (short)p.getFirst().intValue(), null, table); m_voltClient.backpressureBarrier(); } } catch (Exception e) { e.printStackTrace(); System.exit(-1); } } } try { maxOutstandingInvocations.acquire(numPermits); System.err.println("Finished all replicated load work"); } catch (InterruptedException e) { e.printStackTrace(); System.exit(-1); } } items = null; } /** Send to data to VoltDB and/or to the jdbc connection */ private void commitDataTables(long w_id) { if (m_voltClient != null) { commitDataTables_VoltDB(w_id); } for (int i = 0; i < data_tables.length; ++i) { if (data_tables[i] != null) { data_tables[i].clearRowData(); } } } private void commitDataTables_VoltDB(long w_id) { Object[] params = new Object[data_tables.length + 1]; params[0] = (short)w_id; for (int i = 0; i < data_tables.length; ++i) { if (data_tables[i] != null && data_tables[i].getRowCount() > 0) { params[i + 1] = data_tables[i]; } } rethrowExceptionLoad(Constants.LOAD_WAREHOUSE, params); } private void createDataTables() { //customerNames.ensureRowCapacity(parameters.warehouses * parameters.districtsPerWarehouse * parameters.customersPerDistrict); //customerNames.ensureStringCapacity(parameters.warehouses * parameters.districtsPerWarehouse * parameters.customersPerDistrict * (64)); //non replicated tables for (int i = 0; i < data_tables.length; ++i) data_tables[i] = null; data_tables[IDX_WAREHOUSES] = new VoltTable( new VoltTable.ColumnInfo("W_ID", VoltType.SMALLINT), new VoltTable.ColumnInfo("W_NAME", VoltType.STRING), new VoltTable.ColumnInfo("W_STREET_1", VoltType.STRING), new VoltTable.ColumnInfo("W_STREET_2", VoltType.STRING), new VoltTable.ColumnInfo("W_CITY", VoltType.STRING), new VoltTable.ColumnInfo("W_STATE", VoltType.STRING), new VoltTable.ColumnInfo("W_ZIP", VoltType.STRING), new VoltTable.ColumnInfo("W_TAX", VoltType.FLOAT), new VoltTable.ColumnInfo("W_YTD", VoltType.FLOAT) ); //t.ensureRowCapacity(1); //t.ensureStringCapacity(200); data_tables[IDX_DISTRICTS] = new VoltTable( new VoltTable.ColumnInfo("D_ID", VoltType.TINYINT), new VoltTable.ColumnInfo("D_W_ID", VoltType.SMALLINT), new VoltTable.ColumnInfo("D_NAME", VoltType.STRING), new VoltTable.ColumnInfo("D_STREET_1", VoltType.STRING), new VoltTable.ColumnInfo("D_STREET_2", VoltType.STRING), new VoltTable.ColumnInfo("D_CITY", VoltType.STRING), new VoltTable.ColumnInfo("D_STATE", VoltType.STRING), new VoltTable.ColumnInfo("D_ZIP", VoltType.STRING), new VoltTable.ColumnInfo("D_TAX", VoltType.FLOAT), new VoltTable.ColumnInfo("D_YTD", VoltType.FLOAT), new VoltTable.ColumnInfo("D_NEXT_O_ID", VoltType.INTEGER) ); //t.ensureRowCapacity(1); //t.ensureStringCapacity(1 * (16 + 96 + 2 + 9)); data_tables[IDX_CUSTOMERS] = new VoltTable( new VoltTable.ColumnInfo("C_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("C_D_ID", VoltType.TINYINT), new VoltTable.ColumnInfo("C_W_ID", VoltType.SMALLINT), new VoltTable.ColumnInfo("C_FIRST", VoltType.STRING), new VoltTable.ColumnInfo("C_MIDDLE", VoltType.STRING), new VoltTable.ColumnInfo("C_LAST", VoltType.STRING), new VoltTable.ColumnInfo("C_STREET_1", VoltType.STRING), new VoltTable.ColumnInfo("C_STREET_2", VoltType.STRING), new VoltTable.ColumnInfo("C_CITY", VoltType.STRING), new VoltTable.ColumnInfo("C_STATE", VoltType.STRING), new VoltTable.ColumnInfo("C_ZIP", VoltType.STRING), new VoltTable.ColumnInfo("C_PHONE", VoltType.STRING), new VoltTable.ColumnInfo("C_SINCE", VoltType.TIMESTAMP), new VoltTable.ColumnInfo("C_CREDIT", VoltType.STRING), new VoltTable.ColumnInfo("C_CREDIT_LIM", VoltType.FLOAT), new VoltTable.ColumnInfo("C_DISCOUNT", VoltType.FLOAT), new VoltTable.ColumnInfo("C_BALANCE", VoltType.FLOAT), new VoltTable.ColumnInfo("C_YTD_PAYMENT", VoltType.FLOAT), new VoltTable.ColumnInfo("C_PAYMENT_CNT", VoltType.INTEGER), new VoltTable.ColumnInfo("C_DELIVERY_CNT", VoltType.INTEGER), new VoltTable.ColumnInfo("C_DATA", VoltType.STRING) ); //t.ensureRowCapacity(parameters.customersPerDistrict); //t.ensureStringCapacity(parameters.customersPerDistrict * (32 * 6 + 2 * 3 + 9 + 500)); data_tables[IDX_ORDERS] = new VoltTable( new VoltTable.ColumnInfo("O_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("O_D_ID", VoltType.TINYINT), new VoltTable.ColumnInfo("O_W_ID", VoltType.SMALLINT), new VoltTable.ColumnInfo("O_C_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("O_ENTRY_D", VoltType.TIMESTAMP), new VoltTable.ColumnInfo("O_CARRIER_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("O_OL_CNT", VoltType.INTEGER), new VoltTable.ColumnInfo("O_ALL_LOCAL", VoltType.INTEGER) ); //t.ensureRowCapacity(parameters.customersPerDistrict); data_tables[IDX_NEWORDERS] = new VoltTable( new VoltTable.ColumnInfo("NO_O_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("NO_D_ID", VoltType.TINYINT), new VoltTable.ColumnInfo("NO_W_ID", VoltType.SMALLINT) ); //t.ensureRowCapacity(parameters.customersPerDistrict); data_tables[IDX_ORDERLINES] = new VoltTable( new VoltTable.ColumnInfo("OL_O_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("OL_D_ID", VoltType.TINYINT), new VoltTable.ColumnInfo("OL_W_ID", VoltType.SMALLINT), new VoltTable.ColumnInfo("OL_NUMBER", VoltType.INTEGER), new VoltTable.ColumnInfo("OL_I_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("OL_SUPPLY_W_ID", VoltType.SMALLINT), new VoltTable.ColumnInfo("OL_DELIVERY_D", VoltType.TIMESTAMP), new VoltTable.ColumnInfo("OL_QUANTITY", VoltType.INTEGER), new VoltTable.ColumnInfo("OL_AMOUNT", VoltType.FLOAT), new VoltTable.ColumnInfo("OL_DIST_INFO", VoltType.STRING) ); //t.ensureRowCapacity(parameters.customersPerDistrict * Constants.MAX_OL_CNT); //t.ensureStringCapacity(parameters.customersPerDistrict * Constants.MAX_OL_CNT * (32)); data_tables[IDX_HISTORIES] = new VoltTable( new VoltTable.ColumnInfo("H_C_ID", VoltType.INTEGER), new VoltTable.ColumnInfo("H_C_D_ID", VoltType.TINYINT), new VoltTable.ColumnInfo("H_C_W_ID", VoltType.SMALLINT), new VoltTable.ColumnInfo("H_D_ID", VoltType.TINYINT), new VoltTable.ColumnInfo("H_W_ID", VoltType.SMALLINT), new VoltTable.ColumnInfo("H_DATE", VoltType.TIMESTAMP), new VoltTable.ColumnInfo("H_AMOUNT", VoltType.FLOAT), new VoltTable.ColumnInfo("H_DATA", VoltType.STRING) ); //t.ensureRowCapacity(parameters.customersPerDistrict); //t.ensureStringCapacity(parameters.customersPerDistrict * (32)); } } private ConcurrentLinkedQueue<Integer> availableWarehouseIds = new ConcurrentLinkedQueue<Integer>(); public void run() throws NoConnectionsException { ArrayList<Integer> warehouseIds = new ArrayList<Integer>(); for (int ii = 1; ii <= m_warehouses; ii++) { warehouseIds.add(ii); } //Shuffling spreads the loading out across physical hosts better Collections.shuffle(warehouseIds); availableWarehouseIds.addAll(warehouseIds); boolean doMakeReplicated = true; for (LoadThread loadThread : m_loadThreads) { loadThread.start(doMakeReplicated); doMakeReplicated = false; } for (int ii = 0; ii < m_loadThreads.length; ii++) { try { m_loadThreads[ii].join(); } catch (InterruptedException e) { e.printStackTrace(); System.exit(-1); } } try { m_voltClient.drain(); } catch (InterruptedException e) { return; } } }