-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathtpccdb.h
513 lines (432 loc) · 17.7 KB
/
tpccdb.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
#ifndef TPCCDB_H__
#define TPCCDB_H__
#include <stdint.h>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace tpcc {
// was used to select between various non-standard implementations: now use std
template <typename T>
class Set : public std::unordered_set<T> {};
}
// Just a container for constants
struct Address {
// TODO: Embed this structure in warehouse, district, customer? This would reduce some
// duplication, but would also change the field names
static const int MIN_STREET = 10;
static const int MAX_STREET = 20;
static const int MIN_CITY = 10;
static const int MAX_CITY = 20;
static const int STATE = 2;
static const int ZIP = 9;
static void copy(char* street1, char* street2, char* city, char* state, char* zip,
const char* src_street1, const char* src_street2, const char* src_city,
const char* src_state, const char* src_zip);
private:
Address();
};
struct Item {
static const int MIN_IM = 1;
static const int MAX_IM = 10000;
static constexpr float MIN_PRICE = 1.00;
static constexpr float MAX_PRICE = 100.00;
static const int MIN_NAME = 14;
static const int MAX_NAME = 24;
static const int MIN_DATA = 26;
static const int MAX_DATA = 50;
static const int NUM_ITEMS = 100000;
int32_t i_id;
int32_t i_im_id;
float i_price;
char i_name[MAX_NAME+1];
char i_data[MAX_DATA+1];
};
struct Warehouse {
static constexpr float MIN_TAX = 0;
static constexpr float MAX_TAX = 0.2000f;
static constexpr float INITIAL_YTD = 300000.00f;
static const int MIN_NAME = 6;
static const int MAX_NAME = 10;
// TPC-C 1.3.1 (page 11) requires 2*W. This permits testing up to 50 warehouses. This is an
// arbitrary limit created to pack ids into integers.
static const int MAX_WAREHOUSE_ID = 100;
int32_t w_id;
float w_tax;
float w_ytd;
char w_name[MAX_NAME+1];
char w_street_1[Address::MAX_STREET+1];
char w_street_2[Address::MAX_STREET+1];
char w_city[Address::MAX_CITY+1];
char w_state[Address::STATE+1];
char w_zip[Address::ZIP+1];
};
struct District {
static constexpr float MIN_TAX = 0;
static constexpr float MAX_TAX = 0.2000f;
static constexpr float INITIAL_YTD = 30000.00; // different from Warehouse
static const int INITIAL_NEXT_O_ID = 3001;
static const int MIN_NAME = 6;
static const int MAX_NAME = 10;
static const int NUM_PER_WAREHOUSE = 10;
int32_t d_id;
int32_t d_w_id;
float d_tax;
float d_ytd;
int32_t d_next_o_id;
char d_name[MAX_NAME+1];
char d_street_1[Address::MAX_STREET+1];
char d_street_2[Address::MAX_STREET+1];
char d_city[Address::MAX_CITY+1];
char d_state[Address::STATE+1];
char d_zip[Address::ZIP+1];
};
struct Stock {
static const int MIN_QUANTITY = 10;
static const int MAX_QUANTITY = 100;
static const int DIST = 24;
static const int MIN_DATA = 26;
static const int MAX_DATA = 50;
static const int NUM_STOCK_PER_WAREHOUSE = 100000;
int32_t s_i_id;
int32_t s_w_id;
int32_t s_quantity;
int32_t s_ytd;
int32_t s_order_cnt;
int32_t s_remote_cnt;
char s_dist[District::NUM_PER_WAREHOUSE][DIST+1];
char s_data[MAX_DATA+1];
};
// YYYY-MM-DD HH:MM:SS This is supposed to be a date/time field from Jan 1st 1900 -
// Dec 31st 2100 with a resolution of 1 second. See TPC-C 1.3.1.
static const int DATETIME_SIZE = 14;
struct Customer {
static constexpr float INITIAL_CREDIT_LIM = 50000.00;
static constexpr float MIN_DISCOUNT = 0.0000;
static constexpr float MAX_DISCOUNT = 0.5000;
static constexpr float INITIAL_BALANCE = -10.00;
static constexpr float INITIAL_YTD_PAYMENT = 10.00;
static const int INITIAL_PAYMENT_CNT = 1;
static const int INITIAL_DELIVERY_CNT = 0;
static const int MIN_FIRST = 6;
static const int MAX_FIRST = 10;
static const int MIDDLE = 2;
static const int MAX_LAST = 16;
static const int PHONE = 16;
static const int CREDIT = 2;
static const int MIN_DATA = 300;
static const int MAX_DATA = 500;
static const int NUM_PER_DISTRICT = 3000;
static const char GOOD_CREDIT[];
static const char BAD_CREDIT[];
int32_t c_id;
int32_t c_d_id;
int32_t c_w_id;
float c_credit_lim;
float c_discount;
float c_balance;
float c_ytd_payment;
int32_t c_payment_cnt;
int32_t c_delivery_cnt;
char c_first[MAX_FIRST+1];
char c_middle[MIDDLE+1];
char c_last[MAX_LAST+1];
char c_street_1[Address::MAX_STREET+1];
char c_street_2[Address::MAX_STREET+1];
char c_city[Address::MAX_CITY+1];
char c_state[Address::STATE+1];
char c_zip[Address::ZIP+1];
char c_phone[PHONE+1];
char c_since[DATETIME_SIZE+1];
char c_credit[CREDIT+1];
char c_data[MAX_DATA+1];
};
struct Order {
static const int MIN_CARRIER_ID = 1;
static const int MAX_CARRIER_ID = 10;
// HACK: This is not strictly correct, but it works
static const int NULL_CARRIER_ID = 0;
// Less than this value, carrier != null, >= -> carrier == null
static const int NULL_CARRIER_LOWER_BOUND = 2101;
static const int MIN_OL_CNT = 5;
static const int MAX_OL_CNT = 15;
static const int INITIAL_ALL_LOCAL = 1;
static const int INITIAL_ORDERS_PER_DISTRICT = 3000;
// See TPC-C 1.3.1 (page 15)
static const int MAX_ORDER_ID = 10000000;
int32_t o_id;
int32_t o_c_id;
int32_t o_d_id;
int32_t o_w_id;
int32_t o_carrier_id;
int32_t o_ol_cnt;
int32_t o_all_local;
char o_entry_d[DATETIME_SIZE+1];
};
struct OrderLine {
static const int MIN_I_ID = 1;
static const int MAX_I_ID = 100000; // Item::NUM_ITEMS
static const int INITIAL_QUANTITY = 5;
static constexpr float MIN_AMOUNT = 0.01f;
static constexpr float MAX_AMOUNT = 9999.99f;
// new order has 10/1000 probability of selecting a remote warehouse for ol_supply_w_id
static const int REMOTE_PROBABILITY_MILLIS = 10;
int32_t ol_o_id;
int32_t ol_d_id;
int32_t ol_w_id;
int32_t ol_number;
int32_t ol_i_id;
int32_t ol_supply_w_id;
int32_t ol_quantity;
float ol_amount;
char ol_delivery_d[DATETIME_SIZE+1];
char ol_dist_info[Stock::DIST+1];
};
struct NewOrder {
static const int INITIAL_NUM_PER_DISTRICT = 900;
int32_t no_w_id;
int32_t no_d_id;
int32_t no_o_id;
};
struct History {
static const int MIN_DATA = 12;
static const int MAX_DATA = 24;
static constexpr float INITIAL_AMOUNT = 10.00f;
int32_t h_c_id;
int32_t h_c_d_id;
int32_t h_c_w_id;
int32_t h_d_id;
int32_t h_w_id;
float h_amount;
char h_date[DATETIME_SIZE+1];
char h_data[MAX_DATA+1];
};
// Data returned by the "order status" transaction.
struct OrderStatusOutput {
// From customer
int32_t c_id; // unclear if this needs to be returned
float c_balance;
// From order
int32_t o_id;
int32_t o_carrier_id;
struct OrderLineSubset {
int32_t ol_i_id;
int32_t ol_supply_w_id;
int32_t ol_quantity;
float ol_amount;
char ol_delivery_d[DATETIME_SIZE+1];
};
std::vector<OrderLineSubset> lines;
// From customer
char c_first[Customer::MAX_FIRST+1];
char c_middle[Customer::MIDDLE+1];
char c_last[Customer::MAX_LAST+1];
// From order
char o_entry_d[DATETIME_SIZE+1];
};
struct NewOrderItem {
int32_t i_id;
int32_t ol_supply_w_id;
int32_t ol_quantity;
};
struct NewOrderOutput {
// Zero initialize everything. This avoids copying uninitialized data around when
// serializing/deserializing.
NewOrderOutput() : w_tax(0), d_tax(0), o_id(0), c_discount(0), total(0) {
memset(c_last, 0, sizeof(c_last));
memset(c_credit, 0, sizeof(c_credit));
memset(status, 0, sizeof(status));
}
float w_tax;
float d_tax;
// From district d_next_o_id
int32_t o_id;
float c_discount;
// TODO: Client can compute this from other values.
float total;
struct ItemInfo {
static const char BRAND = 'B';
static const char GENERIC = 'G';
int32_t s_quantity;
float i_price;
// TODO: Client can compute this from other values.
float ol_amount;
char brand_generic;
char i_name[Item::MAX_NAME+1];
};
std::vector<ItemInfo> items;
char c_last[Customer::MAX_LAST+1];
char c_credit[Customer::CREDIT+1];
static const int MAX_STATUS = 25;
static const char INVALID_ITEM_STATUS[];
char status[MAX_STATUS+1];
};
struct PaymentOutput {
// TPC-C 2.5.3.4 specifies these output fields
char w_street_1[Address::MAX_STREET+1];
char w_street_2[Address::MAX_STREET+1];
char w_city[Address::MAX_CITY+1];
char w_state[Address::STATE+1];
char w_zip[Address::ZIP+1];
char d_street_1[Address::MAX_STREET+1];
char d_street_2[Address::MAX_STREET+1];
char d_city[Address::MAX_CITY+1];
char d_state[Address::STATE+1];
char d_zip[Address::ZIP+1];
float c_credit_lim;
float c_discount;
float c_balance;
char c_first[Customer::MAX_FIRST+1];
char c_middle[Customer::MIDDLE+1];
char c_last[Customer::MAX_LAST+1];
char c_street_1[Address::MAX_STREET+1];
char c_street_2[Address::MAX_STREET+1];
char c_city[Address::MAX_CITY+1];
char c_state[Address::STATE+1];
char c_zip[Address::ZIP+1];
char c_phone[Customer::PHONE+1];
char c_since[DATETIME_SIZE+1];
char c_credit[Customer::CREDIT+1];
char c_data[Customer::MAX_DATA+1];
};
struct DeliveryOrderInfo {
int32_t d_id;
int32_t o_id;
};
// Contains data required to undo transactions. Note that only new order, payment, and delivery
// update the database. This structure only contains information to undo these transactions.
class TPCCUndo {
public:
~TPCCUndo();
void save(Warehouse* w);
void save(District* d);
void save(Customer* c);
void save(Stock* s);
void save(Order* o);
void save(OrderLine* o);
void inserted(const Order* o);
void inserted(const OrderLine* ol);
void inserted(const NewOrder* no);
void inserted(const History* h);
void deleted(NewOrder* no);
// Marks this undo buffer as applied. This prevents the destructor from deleting tuples
// marked as deleted.
void applied();
typedef std::unordered_map<Warehouse*, Warehouse*> WarehouseMap;
const WarehouseMap& modified_warehouses() const { return modified_warehouses_; }
typedef std::unordered_map<District*, District*> DistrictMap;
const DistrictMap& modified_districts() const { return modified_districts_; }
typedef std::unordered_map<Customer*, Customer*> CustomerMap;
const CustomerMap& modified_customers() const { return modified_customers_; }
typedef std::unordered_map<Stock*, Stock*> StockMap;
const StockMap& modified_stock() const { return modified_stock_; }
typedef std::unordered_map<Order*, Order*> OrderMap;
const OrderMap& modified_orders() const { return modified_orders_; }
typedef std::unordered_map<OrderLine*, OrderLine*> OrderLineMap;
const OrderLineMap& modified_order_lines() const { return modified_order_lines_; }
typedef tpcc::Set<const Order*> OrderSet;
const OrderSet& inserted_orders() const { return inserted_orders_; }
typedef tpcc::Set<const OrderLine*> OrderLineSet;
const OrderLineSet& inserted_order_lines() const { return inserted_order_lines_; }
typedef tpcc::Set<const NewOrder*> NewOrderSet;
const NewOrderSet& inserted_new_orders() const { return inserted_new_orders_; }
typedef tpcc::Set<NewOrder*> NewOrderDeletedSet;
const NewOrderDeletedSet& deleted_new_orders() const { return deleted_new_orders_; }
typedef tpcc::Set<const History*> HistorySet;
const HistorySet& inserted_history() const { return inserted_history_; }
private:
WarehouseMap modified_warehouses_;
DistrictMap modified_districts_;
CustomerMap modified_customers_;
StockMap modified_stock_;
OrderMap modified_orders_;
OrderLineMap modified_order_lines_;
OrderSet inserted_orders_;
OrderLineSet inserted_order_lines_;
NewOrderSet inserted_new_orders_;
HistorySet inserted_history_;
NewOrderDeletedSet deleted_new_orders_;
};
// Interface to the TPC-C transaction implementation.
//
// Undoing transactions: If the TPCCUndo** undo parameter is not null, and the transaction modifies
// the database, then a TPCCUndo structure will either be allocated or extended. This structure can
// then be passed to applyUndo() to undo the effects of the transaction, or to freeUndo() to
// deallocate it. If *undo is NULL, that means the transaction did not modify the database.
//
// NOTE: stockLevel and orderStatus are read-only, and thus don't need undo.
class TPCCDB {
public:
virtual ~TPCCDB() {}
// Executes the TPC-C "slev" transaction. From the last 20 orders, returns the number of rows in
// the STOCK table that have S_QUANTITY < threshold. See TPC-C 2.8 (page 43).
virtual int32_t stockLevel(int32_t warehouse_id, int32_t district_id, int32_t threshold) = 0;
// Executes the TPC-C order status transaction. Find the customer's last order and check the
// delivery date of each item on the order. See TPC-C 2.6 (page 36).
virtual void orderStatus(int32_t warehouse_id, int32_t district_id, int32_t customer_id,
OrderStatusOutput* output) = 0;
// Executes the TPC-C order status transaction. Find the customer's last order and check the
// delivery date of each item on the order. See TPC-C 2.6 (page 36).
virtual void orderStatus(int32_t warehouse_id, int32_t district_id, const char* c_last,
OrderStatusOutput* output) = 0;
// Executes the TPC-C new order transaction. Enter the new order for customer_id into the
// database. See TPC-C 2.4 (page 27). Returns true if the transaction commits.
virtual bool newOrder(int32_t warehouse_id, int32_t district_id, int32_t customer_id,
const std::vector<NewOrderItem>& items, const char* now,
NewOrderOutput* output, TPCCUndo** undo) = 0;
// Executes the "home warehouse" portion of the new order transaction.
virtual bool newOrderHome(int32_t warehouse_id, int32_t district_id, int32_t customer_id,
const std::vector<NewOrderItem>& items, const char* now,
NewOrderOutput* output, TPCCUndo** undo) = 0;
// Executes the "remote warehouse" portion of the new order transaction. Modifies the stock
// for remote_warehouse. Needs access to all the items in order to reach the same commit/abort
// decision as the other warehouses. out_quantities is filled with stock quantities: 0 if the
// item is from another warehouse, or s_quantity if the item is from remote_warehouse.
// TODO: home_warehouse could be replaced with "bool is_remote", which would not need to be
// part of the RPC
virtual bool newOrderRemote(int32_t home_warehouse, int32_t remote_warehouse,
const std::vector<NewOrderItem>& items, std::vector<int32_t>* out_quantities,
TPCCUndo** undo) = 0;
typedef tpcc::Set<int32_t> WarehouseSet;
static WarehouseSet newOrderRemoteWarehouses(int32_t home_warehouse,
const std::vector<NewOrderItem>& items);
static const int32_t INVALID_QUANTITY = -1;
// Combines valid quantities into output.
static void newOrderCombine(const std::vector<int32_t>& remote_quantities,
NewOrderOutput* output);
static void newOrderCombine(const std::vector<int32_t>& quantities,
std::vector<int32_t>* output);
// Executes the TPC-C payment transaction. Add h_amount to the customer's account.
// See TPC-C 2.5 (page 32).
virtual void payment(int32_t warehouse_id, int32_t district_id, int32_t c_warehouse_id,
int32_t c_district_id, int32_t customer_id, float h_amount, const char* now,
PaymentOutput* output, TPCCUndo** undo) = 0;
// Executes the TPC-C payment transaction. Add h_amount to the customer's account.
// See TPC-C 2.5 (page 32).
virtual void payment(int32_t warehouse_id, int32_t district_id, int32_t c_warehouse_id,
int32_t c_district_id, const char* c_last, float h_amount, const char* now,
PaymentOutput* output, TPCCUndo** undo) = 0;
// TODO: See CHEATS: c_id is invalid for customer by last name transactions
virtual void paymentHome(int32_t warehouse_id, int32_t district_id, int32_t c_warehouse_id,
int32_t c_district_id, int32_t c_id, float h_amount, const char* now,
PaymentOutput* output, TPCCUndo** undo) = 0;
virtual void paymentRemote(int32_t warehouse_id, int32_t district_id, int32_t c_warehouse_id,
int32_t c_district_id, int32_t c_id, float h_amount, PaymentOutput* output,
TPCCUndo** undo) = 0;
virtual void paymentRemote(int32_t warehouse_id, int32_t district_id, int32_t c_warehouse_id,
int32_t c_district_id, const char* c_last, float h_amount, PaymentOutput* output,
TPCCUndo** undo) = 0;
// Combines results from paymentRemote in remote into the results from paymentHome in home.
static void paymentCombine(const PaymentOutput& remote, PaymentOutput* home);
// Executes the TPC-C delivery transaction. Delivers the oldest undelivered transaction in each
// district in warehouse_id. See TPC-C 2.7 (page 39).
virtual void delivery(int32_t warehouse_id, int32_t carrier_id, const char* now,
std::vector<DeliveryOrderInfo>* orders, TPCCUndo** undo) = 0;
// Returns true if warehouse_id is present on this partition.
virtual bool hasWarehouse(int32_t warehouse_id) = 0;
// Applies the undo buffer to undo the writes of a transaction.
virtual void applyUndo(TPCCUndo* undo) = 0;
// Frees the undo buffer in undo.
virtual void freeUndo(TPCCUndo* undo) = 0;
};
#endif