Package com

Source Code of com.MyLoader$LoadThread

/* This file is part of VoltDB.
* Copyright (C) 2008-2014 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;
        }
    }
}
TOP

Related Classes of com.MyLoader$LoadThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.