/*************************************************************************** * Copyright (C) 2012 by H-Store Project * * Brown University * * Massachusetts Institute of Technology * * Yale University * * * * Alex Kalinin (akalinin@cs.brown.edu) * * http://www.cs.brown.edu/~akalinin/ * * * * 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 edu.brown.benchmark.tpce.generators; import org.voltdb.catalog.Table; import edu.brown.benchmark.tpce.TPCEConstants; import edu.brown.benchmark.tpce.generators.TPCEGenerator.InputFile; import edu.brown.benchmark.tpce.util.EGenRandom; public class AddressGenerator extends TableGenerator { // For generating address lines private static final int streetNumberMin = 100; private static final int streetNumberMax = 25000; private static final int pctCustomersWithNullAD_LINE_2 = 60; // % of customers that do not have a second address line private static final int pctCustomersWithAptAD_LINE_2 = 75; // % of customer that live in an apartment (others live in a suite) private static final int apartmentNumberMin = 1; private static final int apartmentNumberMax = 1000; private static final int suiteNumberMin = 1; private static final int suiteNumberMax = 500; private static final int USACtryCode = 1; //must be the same as the code in country tax rates file private static final int CanadaCtryCode = 2; //must be the same as the code in country tax rates file private final long customersNum; private final long customersStart; private long counter; private long totalAddresses; // not really "total", just the last row number for hasNext() purposes private boolean isCustomerAddress; // is the currently generated address for a customer? private final long exchangeCount; private final long companyCount; /* * Number of RNG calls to skip for one row in order * to not use any of the random values from the previous row. */ private static final int rngSkipOneRowAddress = 10; // real number in 3.5: 7 private final EGenRandom rnd; private final InputFileHandler streetFile; private final InputFileHandler streetSuffFile; private final InputFileHandler zipFile; public AddressGenerator(Table catalog_tbl, TPCEGenerator generator) { super(catalog_tbl, generator); customersNum = generator.getCustomersNum(); customersStart = generator.getStartCustomer(); rnd = new EGenRandom(EGenRandom.RNG_SEED_TABLE_DEFAULT); exchangeCount = generator.getInputFile(InputFile.EXCHANGE).getRecordsNum(); companyCount = generator.getCompanyCount(generator.getTotalCustomers()); streetFile = generator.getInputFile(InputFile.STNAME); streetSuffFile = generator.getInputFile(InputFile.STSUFFIX); zipFile = generator.getInputFile(InputFile.ZIPCODE); // if we are generating another portion of customers, do not generate exchange/company addresses setCounter(customersStart != TPCEConstants.DEFAULT_START_CUSTOMER_ID); } public void setCounter(boolean customersOnly) { if (customersOnly) { // assume we have already generated addresses for exchanges and companies counter = exchangeCount + companyCount + customersStart - 1; totalAddresses = counter + customersNum; } else { counter = customersStart - 1; totalAddresses = counter + exchangeCount + companyCount + customersNum; } } private void initNextLoadUnit() { rnd.setSeedNth(EGenRandom.RNG_SEED_TABLE_DEFAULT, counter * rngSkipOneRowAddress); } public long generateAddrId() { // if we are generating customer addresses, then reset the generator if needed if (counter > (exchangeCount + companyCount) && ((counter - (exchangeCount + companyCount)) % TPCEConstants.DEFAULT_LOAD_UNIT == 0)) { initNextLoadUnit(); } counter++; isCustomerAddress = (counter >= exchangeCount + companyCount); return counter + TPCEConstants.IDENT_SHIFT; } public long getCurrentAddrId() { return counter + TPCEConstants.IDENT_SHIFT; } public long getAddrIdForCustomer(long custId) { return exchangeCount + companyCount + custId; } private String generateAddrLine1() { int streetNum = rnd.intRange(streetNumberMin, streetNumberMax); int streetNameKey = rnd.intRange(0, streetFile.getMaxKey() - 1); // -1? made this to be compatible with EGen int streetSuffKey = rnd.intRange(0, streetSuffFile.getMaxKey()); return Integer.toString(streetNum) + " " + streetFile.getTupleByKey(streetNameKey)[0] + " " + streetSuffFile.getTupleByKey(streetSuffKey)[0]; } private String generateAddrLine2() { // companies do not have a second line, as some customers (60% by default) if (!isCustomerAddress || rnd.rndPercent(pctCustomersWithNullAD_LINE_2)) { return ""; } else { if (rnd.rndPercent(pctCustomersWithAptAD_LINE_2)) { return "Apt. " + Integer.toString(rnd.intRange(apartmentNumberMin, apartmentNumberMax)); } else { return "Suite " + Integer.toString(rnd.intRange(suiteNumberMin, suiteNumberMax)); } } } private int getZipRecKey(long adId) { long oldSeed = rnd.getSeed(); rnd.setSeedNth(EGenRandom.RNG_SEED_BASE_TOWN_DIV_ZIP, adId); int key = rnd.intRange(0, zipFile.getMaxKey()); rnd.setSeed(oldSeed); return key; } private int getCountryCode(String zipCode) { char c = zipCode.charAt(0); if (c >= '0' && c <= '9') { return USACtryCode; } else { return CanadaCtryCode; } } // returns division and country codes (for tax rate) public int[] getCountryAndDivCodes(long adId) { int[] res = new int[2]; String[] zipRecord = zipFile.getTupleByKey(getZipRecKey(adId)); res[0] = getCountryCode(zipRecord[1]); // country tax code res[1] = Integer.valueOf(zipRecord[0]); // division tax code return res; } private String[] generateZipAndCountry(long adId) { String[] zip_country = new String[2]; int zipKey = getZipRecKey(adId); zip_country[0] = zipFile.getTupleByKey(zipKey)[1]; // zip is as a second field int countryCode = getCountryCode(zip_country[0]); if (countryCode == USACtryCode) { zip_country[1] = "USA"; } else { zip_country[1] = "CANADA"; } return zip_country; } @Override public boolean hasNext() { return counter < totalAddresses; } @Override public Object[] next() { Object tuple[] = new Object[columnsNum]; long adId = generateAddrId(); String[] zip_cntr = generateZipAndCountry(adId); tuple[0] = adId; // ad_id tuple[1] = generateAddrLine1(); // ad_line1 tuple[2] = generateAddrLine2(); // ad_line2 tuple[3] = zip_cntr[0]; // ad_zc_code tuple[4] = zip_cntr[1]; // ad_ctry return tuple; } }