1/*
2 * Legal Notice
3 *
4 * This document and associated source code (the "Work") is a part of a
5 * benchmark specification maintained by the TPC.
6 *
7 * The TPC reserves all right, title, and interest to the Work as provided
8 * under U.S. and international laws, including without limitation all patent
9 * and trademark rights therein.
10 *
11 * No Warranty
12 *
13 * 1.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE INFORMATION
14 * CONTAINED HEREIN IS PROVIDED "AS IS" AND WITH ALL FAULTS, AND THE
15 * AUTHORS AND DEVELOPERS OF THE WORK HEREBY DISCLAIM ALL OTHER
16 * WARRANTIES AND CONDITIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
17 * INCLUDING, BUT NOT LIMITED TO, ANY (IF ANY) IMPLIED WARRANTIES,
18 * DUTIES OR CONDITIONS OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR
19 * PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OF
20 * WORKMANLIKE EFFORT, OF LACK OF VIRUSES, AND OF LACK OF NEGLIGENCE.
21 * ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT,
22 * QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT
23 * WITH REGARD TO THE WORK.
24 * 1.2 IN NO EVENT WILL ANY AUTHOR OR DEVELOPER OF THE WORK BE LIABLE TO
25 * ANY OTHER PARTY FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO THE
26 * COST OF PROCURING SUBSTITUTE GOODS OR SERVICES, LOST PROFITS, LOSS
27 * OF USE, LOSS OF DATA, OR ANY INCIDENTAL, CONSEQUENTIAL, DIRECT,
28 * INDIRECT, OR SPECIAL DAMAGES WHETHER UNDER CONTRACT, TORT, WARRANTY,
29 * OR OTHERWISE, ARISING IN ANY WAY OUT OF THIS OR ANY OTHER AGREEMENT
30 * RELATING TO THE WORK, WHETHER OR NOT SUCH AUTHOR OR DEVELOPER HAD
31 * ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.
32 *
33 * Contributors
34 * - Doug Johnson, Matt Emmerton
35 */
36
37/******************************************************************************
38 * Description: Implementation of the DM class.
39 * See DM.h for a description.
40 ******************************************************************************/
41
42#include "main/DM.h"
43#include "main/StatusTypeIDs.h"
44
45using namespace TPCE;
46
47const INT32 iDataMaintenanceTableCount = 12;
48static const char *DataMaintenanceTableName[iDataMaintenanceTableCount] = {
49 "ACCOUNT_PERMISSION", "ADDRESS", "COMPANY", "CUSTOMER", "CUSTOMER_TAXRATE", "DAILY_MARKET",
50 "EXCHANGE", "FINANCIAL", "NEWS_ITEM", "SECURITY", "TAXRATE", "WATCH_ITEM"};
51
52// Automatically generate unique RNG seeds.
53// The CRandom class uses an unsigned 64-bit value for the seed.
54// This routine automatically generates two unique seeds. One is used for
55// the TxnInput generator RNG, and the other is for the TxnMixGenerator RNG.
56// The 64 bits are used as follows.
57//
58// Bits 0 - 31 Caller provided unique unsigned 32-bit id.
59// Bit 32 0
60// Bits 33 - 43 Number of days since the base time. The base time
61// is set to be January 1 of the most recent year that is
62// a multiple of 5. This allows enough space for the last
63// field, and it makes the algorithm "timeless" by resetting
64// the generated values every 5 years.
65// Bits 44 - 63 Current time of day measured in 1/10's of a second.
66//
67void CDM::AutoSetRNGSeeds(UINT32 UniqueId) {
68 CDateTime Now;
69 INT32 BaseYear;
70 INT32 Tmp1, Tmp2;
71
72 Now.GetYMD(&BaseYear, &Tmp1, &Tmp2);
73
74 // Set the base year to be the most recent year that was a multiple of 5.
75 BaseYear -= (BaseYear % 5);
76 CDateTime Base(BaseYear, 1, 1); // January 1st in the BaseYear
77
78 // Initialize the seed with the current time of day measured in 1/10's of a
79 // second. This will use up to 20 bits.
80 RNGSEED Seed;
81 Seed = Now.MSec() / 100;
82
83 // Now add in the number of days since the base time.
84 // The number of days in the 5 year period requires 11 bits.
85 // So shift up by that much to make room in the "lower" bits.
86 Seed <<= 11;
87 Seed += (RNGSEED)((INT64)Now.DayNo() - (INT64)Base.DayNo());
88
89 // So far, we've used up 31 bits.
90 // Save the "last" bit of the "upper" 32 for the RNG id. In
91 // this case, it is always 0 since we don't have a second
92 // RNG in this class.
93 // In addition, make room for the caller's 32-bit unique id.
94 // So shift a total of 33 bits.
95 Seed <<= 33;
96
97 // Now the "upper" 32-bits have been set with a value for RNG 0.
98 // Add in the sponsor's unique id for the "lower" 32-bits.
99 Seed += UniqueId;
100
101 // Set the RNG to the unique seed.
102 m_rnd.SetSeed(Seed);
103 m_DriverDMSettings.cur.RNGSeed = Seed;
104}
105
106void CDM::Initialize(void) {
107 m_pLogger->SendToLogger(m_DriverGlobalSettings);
108
109 m_iSecurityCount = m_Securities.GetActiveSecurityCount();
110 m_iCompanyCount = m_Companies.GetActiveCompanyCount();
111 m_iStartFromCompany = m_Companies.GetCompanyId(0);
112 m_iDivisionTaxCount = m_TaxRatesDivision.size(m_TaxRatesDivision.BucketsOnly);
113 m_iStartFromCustomer = iDefaultStartFromCustomer + iTIdentShift;
114}
115
116CDM::CDM(CDMSUTInterface *pSUT, CBaseLogger *pLogger, const DataFileManager &dfm, TIdent iConfiguredCustomerCount,
117 TIdent iActiveCustomerCount, INT32 iScaleFactor, INT32 iDaysOfInitialTrades, UINT32 UniqueId)
118 : m_DriverGlobalSettings(iConfiguredCustomerCount, iActiveCustomerCount, iScaleFactor, iDaysOfInitialTrades),
119 m_DriverDMSettings(UniqueId, 0), m_CustomerSelection(&m_rnd, iDefaultStartFromCustomer, iActiveCustomerCount),
120 m_AccsAndPerms(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer),
121 m_Securities(dfm.SecurityFile()), m_Companies(dfm.CompanyFile()),
122 m_TaxRatesDivision(dfm.TaxRateDivisionDataFile()), m_StatusType(dfm.StatusTypeDataFile()), m_iDivisionTaxCount(0),
123 m_DataMaintenanceTableNum(0), m_pSUT(pSUT), m_pLogger(pLogger) {
124 m_pLogger->SendToLogger("DM object constructed using constructor 1 (valid "
125 "for publication: YES).");
126
127 Initialize();
128 AutoSetRNGSeeds(UniqueId);
129
130 m_pLogger->SendToLogger(m_DriverDMSettings); // log the RNG seeds
131}
132
133CDM::CDM(CDMSUTInterface *pSUT, CBaseLogger *pLogger, const DataFileManager &dfm, TIdent iConfiguredCustomerCount,
134 TIdent iActiveCustomerCount, INT32 iScaleFactor, INT32 iDaysOfInitialTrades, UINT32 UniqueId, RNGSEED RNGSeed)
135 : m_DriverGlobalSettings(iConfiguredCustomerCount, iActiveCustomerCount, iScaleFactor, iDaysOfInitialTrades),
136 m_DriverDMSettings(UniqueId, RNGSeed), m_rnd(RNGSeed),
137 m_CustomerSelection(&m_rnd, iDefaultStartFromCustomer, iActiveCustomerCount),
138 m_AccsAndPerms(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer),
139 m_Securities(dfm.SecurityFile()), m_Companies(dfm.CompanyFile()),
140 m_TaxRatesDivision(dfm.TaxRateDivisionDataFile()), m_StatusType(dfm.StatusTypeDataFile()), m_iDivisionTaxCount(0),
141 m_DataMaintenanceTableNum(0), m_pSUT(pSUT), m_pLogger(pLogger) {
142 m_pLogger->SendToLogger("DM object constructed using constructor 2 (valid "
143 "for publication: NO).");
144
145 Initialize();
146
147 m_pLogger->SendToLogger(m_DriverDMSettings); // log the RNG seeds
148}
149
150CDM::~CDM() {
151 m_pLogger->SendToLogger("DM object destroyed.");
152}
153
154TIdent CDM::GenerateRandomCustomerId() {
155 return m_rnd.RndInt64Range(m_iStartFromCustomer,
156 m_iStartFromCustomer + m_DriverGlobalSettings.cur.iActiveCustomerCount - 1);
157}
158
159TIdent CDM::GenerateRandomCustomerAccountId() {
160 TIdent iCustomerId;
161
162 eCustomerTier iCustomerTier;
163
164 m_CustomerSelection.GenerateRandomCustomer(iCustomerId, iCustomerTier);
165
166 return (m_AccsAndPerms.GenerateRandomAccountId(m_rnd, iCustomerId, iCustomerTier));
167}
168
169TIdent CDM::GenerateRandomCompanyId() {
170 return m_rnd.RndInt64Range(m_iStartFromCompany, m_iStartFromCompany + m_iCompanyCount - 1);
171}
172
173TIdent CDM::GenerateRandomSecurityId() {
174 return m_rnd.RndInt64Range(0, m_iSecurityCount - 1);
175}
176
177RNGSEED CDM::GetRNGSeed(void) {
178 return (m_rnd.GetSeed());
179}
180
181void CDM::DoTxn(void) {
182 m_TxnInput.Clear();
183 strncpy(m_TxnInput.table_name, DataMaintenanceTableName[m_DataMaintenanceTableNum], sizeof(m_TxnInput.table_name));
184
185 switch (m_DataMaintenanceTableNum) {
186 case 0: // ACCOUNT_PERMISSION
187 m_TxnInput.acct_id = GenerateRandomCustomerAccountId();
188 break;
189 case 1: // ADDRESS
190 if (m_rnd.RndPercent(67)) {
191 m_TxnInput.c_id = GenerateRandomCustomerId();
192 } else {
193 m_TxnInput.co_id = GenerateRandomCompanyId();
194 }
195 break;
196 case 2: // COMPANY
197 m_TxnInput.co_id = GenerateRandomCompanyId();
198 break;
199 case 3: // CUSTOMER
200 m_TxnInput.c_id = GenerateRandomCustomerId();
201 break;
202 case 4: // CUSTOMER_TAXRATE
203 m_TxnInput.c_id = GenerateRandomCustomerId();
204 break;
205 case 5: // DAILY_MARKET
206 m_Securities.CreateSymbol(GenerateRandomSecurityId(), m_TxnInput.symbol,
207 static_cast<int>(sizeof(m_TxnInput.symbol)));
208 m_TxnInput.day_of_month = m_rnd.RndIntRange(1, 31);
209 m_TxnInput.vol_incr = m_rnd.RndIntRange(-2, 3);
210 if (m_TxnInput.vol_incr == 0) // don't want 0 as increment
211 {
212 m_TxnInput.vol_incr = -3;
213 }
214 break;
215 case 6: // EXCHANGE
216 break;
217 case 7: // FINANCIAL
218 m_TxnInput.co_id = GenerateRandomCompanyId();
219 break;
220 case 8: // NEWS_ITEM
221 m_TxnInput.co_id = GenerateRandomCompanyId();
222 break;
223 case 9: // SECURITY
224 m_Securities.CreateSymbol(GenerateRandomSecurityId(), m_TxnInput.symbol,
225 static_cast<int>(sizeof(m_TxnInput.symbol)));
226 break;
227 case 10: // TAXRATE
228 {
229 UINT bucketIdx = static_cast<UINT>(m_rnd.RndIntRange(0, m_iDivisionTaxCount - 1));
230 UINT recordIdx = static_cast<UINT>(m_rnd.RndIntRange(0, m_TaxRatesDivision[bucketIdx].size() - 1));
231
232 strncpy(m_TxnInput.tx_id, m_TaxRatesDivision[bucketIdx][recordIdx].TX_ID_CSTR(), sizeof(m_TxnInput.tx_id));
233 } break;
234 case 11: // WATCH_ITEM
235 m_TxnInput.c_id = GenerateRandomCustomerId();
236 break;
237
238 default:
239 assert(false); // should never happen
240 }
241
242 m_pSUT->DataMaintenance(&m_TxnInput);
243
244 m_DataMaintenanceTableNum = (m_DataMaintenanceTableNum + 1) % iDataMaintenanceTableCount;
245}
246
247void CDM::DoCleanupTxn(void) {
248 memset(&m_CleanupTxnInput, 0, sizeof(m_CleanupTxnInput));
249
250 // Compute Starting Trade ID (Copied from CETxnInputGenerator.cpp)
251 m_CleanupTxnInput.start_trade_id =
252 (TTrade)((m_DriverGlobalSettings.cur.iDaysOfInitialTrades * (TTrade)HoursPerWorkDay * (TTrade)SecondsPerHour *
253 (m_DriverGlobalSettings.cur.iConfiguredCustomerCount / m_DriverGlobalSettings.cur.iScaleFactor)) *
254 iAbortTrade / 100) +
255 1 + iTTradeShift; // 1.01 to account for rollbacks, +1 to get first
256 // runtime trade
257
258 // Copy the status type id's from the flat file
259 strncpy(m_CleanupTxnInput.st_pending_id, m_StatusType[ePending].ST_ID_CSTR(),
260 sizeof(m_CleanupTxnInput.st_pending_id));
261 strncpy(m_CleanupTxnInput.st_submitted_id, m_StatusType[eSubmitted].ST_ID_CSTR(),
262 sizeof(m_CleanupTxnInput.st_submitted_id));
263 strncpy(m_CleanupTxnInput.st_canceled_id, m_StatusType[eCanceled].ST_ID_CSTR(),
264 sizeof(m_CleanupTxnInput.st_canceled_id));
265
266 // Execute Transaction
267 m_pSUT->TradeCleanup(&m_CleanupTxnInput);
268}
269