/*************************************************************************** * 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 java.util.HashMap; import java.util.Map; import edu.brown.benchmark.tpce.TPCEConstants; import edu.brown.benchmark.tpce.generators.TPCEGenerator.InputFile; public class SecurityHandler { /* * EGen uses a small set of values for 26 raised to a power, so store them in * a constant array to save doing calls to pow( 26.0, ? ) */ private static final int[] power26 = {1, 26, 676, 17576, 456976, 11881376, 308915776}; // For index i > 0, this array holds the sum of 26^0 ... 26^(i-1) private static final long[] power26Sum = {0, 1, 27, 703, 18279, 475255, 12356631, 321272407, 8353082583L}; private static final char suffSep = '-'; private final InputFileHandler secFile; private final int secRecords; private final int compRecords; private final Map<String, Long> symbolToIdMap = new HashMap<String, Long>(); public SecurityHandler(TPCEGenerator generator) { secFile = generator.getInputFile(InputFile.SECURITY); secRecords = secFile.getRecordsNum(); compRecords = generator.getInputFile(InputFile.COMPANY).getRecordsNum(); } /** * @param maxLen The maximum length for the suffix * @see #createSymbol(long, int) */ private static String createSuffix(long part, int maxLen) { // compute the number of chars to add int charCount = 0; while (part - power26Sum[charCount + 1] >= 0) { charCount++; } String suff = ""; if (charCount + 1 <= maxLen) { // 1 extra for the separator suff += suffSep; /* * charCount is the number of letters needed in the suffix * The base string is a string of 'a's of length charCount * Find the offset from the base value represented by the string * of 'a's to the desired number, and modify the base string * accordingly. */ long offset = part - power26Sum[charCount]; while (charCount > 0) { long lclIndex = offset / power26[charCount - 1]; // lower case letter index suff += ('a' + lclIndex); // assuming lower case letters go continuously offset -= (lclIndex * power26[charCount - 1]); charCount--; } } else { // Not enough room in the string -- go with separators charCount = maxLen; while (charCount-- > 0) { suff += suffSep; } } return suff; } private long parseSuffix(String suffix) { int suffixLen = suffix.length(); long multiplier = power26Sum[suffixLen]; for (int i = 0; i < suffix.length(); i++) { multiplier += power26[suffixLen - 1] * (suffix.charAt(i) - 'a'); // assuming lower case letters go continuously suffixLen--; } return multiplier; } public long getCompanyId(long counter) { return Long.valueOf(getSecRecord(counter)[5]) + TPCEConstants.IDENT_SHIFT + + counter / secRecords * compRecords; } /** * Return the record based on the counter. The file wraps around. */ public String[] getSecRecord(long counter) { return secFile.getTupleByIndex((int)(counter % secRecords)); } /** * @param maxLen The maximum length of the returned symbol (we have SQL type restrictions on that) * For example, daily_market table has a restriction of 15 chars. */ public String createSymbol(long index, int maxLen) { int fileInd = (int)(index % secRecords); long part = index / secRecords; String res = secFile.getTupleByIndex(fileInd)[2]; // symbol is a 2nd field if (part > 0) { res += createSuffix(part, maxLen - res.length()); } assert(res.length() <= maxLen); return res; } public static long getSecurityNum(long customersNum) { return customersNum / TPCEConstants.DEFAULT_LOAD_UNIT * TPCEConstants.DEFAULT_SECURITIES_PER_UNIT; } public static long getSecurityStart(long customerStart) { return customerStart / TPCEConstants.DEFAULT_LOAD_UNIT * TPCEConstants.DEFAULT_SECURITIES_PER_UNIT; } public void loadSymbolToIdMap() { if (symbolToIdMap.isEmpty()) { for (int i = 0; i < secFile.getRecordsNum(); i++) { String[] secTuple = secFile.getTupleByIndex(i); symbolToIdMap.put(secTuple[2], Long.valueOf(secTuple[0])); } } } public long getId(String symbol) { if (symbolToIdMap.isEmpty()) { loadSymbolToIdMap(); } // first, look for the separator -- '-' int sepIndex = symbol.indexOf('-'); if (sepIndex == -1) { // simple name, no suffix return symbolToIdMap.get(symbol); } // suffix present, have to parse it long baseId = symbolToIdMap.get(symbol.substring(0, sepIndex)); long multiplier = parseSuffix(symbol.substring(sepIndex + 1)); return multiplier * secFile.getRecordsNum() + baseId; } public long getCompanyIndex(long counter){ return getCompanyId(counter) - 1 - TPCEConstants.IDENT_SHIFT; } public long getIndex( String pSymbol ) { // Indices and Id's are offset by 1 return( getId( pSymbol ) - 1 ); } }