Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ TFuture<void> TTerminal::Run() {
std::chrono::microseconds latencyPure{0};
bool fatal = false;

// Reset so each business transaction gets fresh inputs; retries reuse FixedInputs.
Context.FixedInputs.reset();

constexpr int MaxRetries = 3;
for (int attempt = 0; attempt <= MaxRetries; ++attempt) {
bool shouldRetry = false;
Expand Down
16 changes: 14 additions & 2 deletions src/transaction_delivery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,20 @@ TFuture<bool> GetDeliveryTask(
TTransactionInflightGuard guard;
co_await TTaskReady(context.TaskQueue, context.TerminalID);

const int warehouseID = context.WarehouseID;
const int carrierID = RandomNumber(1, 10);
struct TInputs {
int WarehouseID;
int CarrierID;
};

const auto& in = FixedTransactionInputs<TInputs>(context, [&] {
return TInputs{
.WarehouseID = static_cast<int>(context.WarehouseID),
.CarrierID = static_cast<int>(RandomNumber(1, 10)),
};
});

const int warehouseID = in.WarehouseID;
const int carrierID = in.CarrierID;

LOG_T("Terminal {} started Delivery: W={}", context.TerminalID, warehouseID);

Expand Down
87 changes: 54 additions & 33 deletions src/transaction_neworder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,42 +67,63 @@ TFuture<bool> GetNewOrderTask(
TTransactionInflightGuard guard;
co_await TTaskReady(context.TaskQueue, context.TerminalID);

const int warehouseID = context.WarehouseID;
const int districtID = RandomNumber(DISTRICT_LOW_ID, DISTRICT_HIGH_ID);
const int customerID = GetRandomCustomerID();

LOG_T("Terminal {} started NewOrder: W={}, D={}, C={}", context.TerminalID, warehouseID, districtID, customerID);

const int numItems = RandomNumber(MIN_ITEMS, MAX_ITEMS);

std::vector<int> itemIDs;
std::vector<int> supplierWarehouseIDs;
std::vector<int> orderQuantities;
itemIDs.reserve(numItems);
supplierWarehouseIDs.reserve(numItems);
orderQuantities.reserve(numItems);
int allLocal = 1;
struct TInputs {
int WarehouseID;
int DistrictID;
int CustomerID;
int NumItems;
std::vector<int> ItemIDs;
std::vector<int> SupplierWarehouseIDs;
std::vector<int> OrderQuantities;
int AllLocal;
bool HasInvalidItem;
};

const auto& in = FixedTransactionInputs<TInputs>(context, [&] {
TInputs generated;
generated.WarehouseID = static_cast<int>(context.WarehouseID);
generated.DistrictID = RandomNumber(DISTRICT_LOW_ID, DISTRICT_HIGH_ID);
generated.CustomerID = GetRandomCustomerID();
generated.NumItems = RandomNumber(MIN_ITEMS, MAX_ITEMS);
generated.ItemIDs.reserve(generated.NumItems);
generated.SupplierWarehouseIDs.reserve(generated.NumItems);
generated.OrderQuantities.reserve(generated.NumItems);
generated.AllLocal = 1;

for (int i = 0; i < generated.NumItems; ++i) {
generated.ItemIDs.push_back(GetRandomItemID());
if (RandomNumber(1, 100) > 1) {
generated.SupplierWarehouseIDs.push_back(generated.WarehouseID);
} else {
int supplierID;
do {
supplierID = RandomNumber(1, context.WarehouseCount);
} while (supplierID == generated.WarehouseID && context.WarehouseCount > 1);
generated.SupplierWarehouseIDs.push_back(supplierID);
generated.AllLocal = 0;
}
generated.OrderQuantities.push_back(RandomNumber(1, 10));
}

for (int i = 0; i < numItems; ++i) {
itemIDs.push_back(GetRandomItemID());
if (RandomNumber(1, 100) > 1) {
supplierWarehouseIDs.push_back(warehouseID);
} else {
int supplierID;
do {
supplierID = RandomNumber(1, context.WarehouseCount);
} while (supplierID == warehouseID && context.WarehouseCount > 1);
supplierWarehouseIDs.push_back(supplierID);
allLocal = 0;
generated.HasInvalidItem = false;
if (RandomNumber(1, 100) == 1) {
generated.ItemIDs[generated.NumItems - 1] = INVALID_ITEM_ID;
generated.HasInvalidItem = true;
}
orderQuantities.push_back(RandomNumber(1, 10));
}
return generated;
});

const int warehouseID = in.WarehouseID;
const int districtID = in.DistrictID;
const int customerID = in.CustomerID;
const int numItems = in.NumItems;
const auto& itemIDs = in.ItemIDs;
const auto& supplierWarehouseIDs = in.SupplierWarehouseIDs;
const auto& orderQuantities = in.OrderQuantities;
const int allLocal = in.AllLocal;
const bool hasInvalidItem = in.HasInvalidItem;

bool hasInvalidItem = false;
if (RandomNumber(1, 100) == 1) {
itemIDs[numItems - 1] = INVALID_ITEM_ID;
hasInvalidItem = true;
}
LOG_T("Terminal {} started NewOrder: W={}, D={}, C={}", context.TerminalID, warehouseID, districtID, customerID);

// Get customer discount/credit
auto custFuture = session.ExecuteQuery(
Expand Down
33 changes: 27 additions & 6 deletions src/transaction_orderstatus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,38 @@ TFuture<bool> GetOrderStatusTask(
TTransactionInflightGuard guard;
co_await TTaskReady(context.TaskQueue, context.TerminalID);

const int warehouseID = context.WarehouseID;
const int districtID = RandomNumber(DISTRICT_LOW_ID, DISTRICT_HIGH_ID);
struct TInputs {
int WarehouseID;
int DistrictID;
bool LookupByName;
std::string LastName;
int CustomerID;
};

const auto& in = FixedTransactionInputs<TInputs>(context, [&] {
TInputs generated;
generated.WarehouseID = static_cast<int>(context.WarehouseID);
generated.DistrictID = RandomNumber(DISTRICT_LOW_ID, DISTRICT_HIGH_ID);
generated.LookupByName = RandomNumber(1, 100) <= 60;
if (generated.LookupByName) {
generated.LastName = GetNonUniformRandomLastNameForRun();
generated.CustomerID = 0;
} else {
generated.CustomerID = GetRandomCustomerID();
}
return generated;
});

LOG_T("Terminal {} started OrderStatus: W={}, D={}", context.TerminalID, warehouseID, districtID);
const int warehouseID = in.WarehouseID;
const int districtID = in.DistrictID;
const bool lookupByName = in.LookupByName;

bool lookupByName = RandomNumber(1, 100) <= 60;
LOG_T("Terminal {} started OrderStatus: W={}, D={}", context.TerminalID, warehouseID, districtID);

TCustomer customer;

if (lookupByName) {
std::string lastName = GetNonUniformRandomLastNameForRun();
const std::string& lastName = in.LastName;

auto custFuture = GetCustomersByLastName(session, warehouseID, districtID, lastName);
auto custResult = co_await TSuspendWithFuture(std::move(custFuture), context.TaskQueue, context.TerminalID);
Expand All @@ -45,7 +66,7 @@ TFuture<bool> GetOrderStatusTask(
}
customer = std::move(*selectedCustomer);
} else {
int customerID = GetRandomCustomerID();
const int customerID = in.CustomerID;

auto custFuture = GetCustomerById(session, warehouseID, districtID, customerID);
auto custResult = co_await TSuspendWithFuture(std::move(custFuture), context.TaskQueue, context.TerminalID);
Expand Down
67 changes: 45 additions & 22 deletions src/transaction_payment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,48 @@ TFuture<bool> GetPaymentTask(
TTransactionInflightGuard guard;
co_await TTaskReady(context.TaskQueue, context.TerminalID);

const int warehouseID = context.WarehouseID;
const int districtID = RandomNumber(DISTRICT_LOW_ID, DISTRICT_HIGH_ID);
const double paymentAmount = static_cast<double>(RandomNumber(100, 500000)) / 100.0;
struct TInputs {
int WarehouseID;
int DistrictID;
double PaymentAmount;
int CustomerDistrictID;
int CustomerWarehouseID;
bool LookupByName;
std::string LastName;
int CustomerID;
};

const auto& in = FixedTransactionInputs<TInputs>(context, [&] {
TInputs generated;
generated.WarehouseID = static_cast<int>(context.WarehouseID);
generated.DistrictID = RandomNumber(DISTRICT_LOW_ID, DISTRICT_HIGH_ID);
generated.PaymentAmount = static_cast<double>(RandomNumber(100, 500000)) / 100.0;

if (RandomNumber(1, 100) <= 85) {
generated.CustomerDistrictID = generated.DistrictID;
generated.CustomerWarehouseID = generated.WarehouseID;
} else {
generated.CustomerDistrictID = RandomNumber(DISTRICT_LOW_ID, DISTRICT_HIGH_ID);
do {
generated.CustomerWarehouseID = RandomNumber(1, context.WarehouseCount);
} while (generated.CustomerWarehouseID == generated.WarehouseID && context.WarehouseCount > 1);
}

generated.LookupByName = RandomNumber(1, 100) <= 60;
if (generated.LookupByName) {
generated.LastName = GetNonUniformRandomLastNameForRun();
generated.CustomerID = 0;
} else {
generated.CustomerID = GetRandomCustomerID();
}
return generated;
});

const int warehouseID = in.WarehouseID;
const int districtID = in.DistrictID;
const double paymentAmount = in.PaymentAmount;
const int customerDistrictID = in.CustomerDistrictID;
const int customerWarehouseID = in.CustomerWarehouseID;

LOG_T("Terminal {} started Payment: W={}, D={}", context.TerminalID, warehouseID, districtID);

Expand Down Expand Up @@ -58,25 +97,10 @@ TFuture<bool> GetPaymentTask(
}
std::string districtName = distResult.GetString("d_name");

// Determine customer warehouse/district
int customerDistrictID;
int customerWarehouseID;

if (RandomNumber(1, 100) <= 85) {
customerDistrictID = districtID;
customerWarehouseID = warehouseID;
} else {
customerDistrictID = RandomNumber(DISTRICT_LOW_ID, DISTRICT_HIGH_ID);
do {
customerWarehouseID = RandomNumber(1, context.WarehouseCount);
} while (customerWarehouseID == warehouseID && context.WarehouseCount > 1);
}

TCustomer customer;

if (RandomNumber(1, 100) <= 60) {
// Look up by last name
std::string lastName = GetNonUniformRandomLastNameForRun();
if (in.LookupByName) {
const std::string& lastName = in.LastName;

auto custFuture = GetCustomersByLastName(session, customerWarehouseID, customerDistrictID, lastName);
auto custResult = co_await TSuspendWithFuture(std::move(custFuture), context.TaskQueue, context.TerminalID);
Expand All @@ -89,8 +113,7 @@ TFuture<bool> GetPaymentTask(
}
customer = std::move(*selectedCustomer);
} else {
// Look up by ID
int customerID = GetRandomCustomerID();
const int customerID = in.CustomerID;

auto custFuture = GetCustomerById(session, customerWarehouseID, customerDistrictID, customerID);
auto custResult = co_await TSuspendWithFuture(std::move(custFuture), context.TaskQueue, context.TerminalID);
Expand Down
20 changes: 17 additions & 3 deletions src/transaction_stocklevel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,23 @@ TFuture<bool> GetStockLevelTask(
TTransactionInflightGuard guard;
co_await TTaskReady(context.TaskQueue, context.TerminalID);

const int warehouseID = context.WarehouseID;
const int districtID = RandomNumber(DISTRICT_LOW_ID, DISTRICT_HIGH_ID);
const int threshold = RandomNumber(10, 20);
struct TInputs {
int WarehouseID;
int DistrictID;
int Threshold;
};

const auto& in = FixedTransactionInputs<TInputs>(context, [&] {
return TInputs{
.WarehouseID = static_cast<int>(context.WarehouseID),
.DistrictID = static_cast<int>(RandomNumber(DISTRICT_LOW_ID, DISTRICT_HIGH_ID)),
.Threshold = static_cast<int>(RandomNumber(10, 20)),
};
});

const int warehouseID = in.WarehouseID;
const int districtID = in.DistrictID;
const int threshold = in.Threshold;

LOG_T("Terminal {} started StockLevel: W={}, D={}", context.TerminalID, warehouseID, districtID);

Expand Down
14 changes: 14 additions & 0 deletions src/transactions.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <atomic>
#include <chrono>
#include <memory>
#include <utility>

namespace NTPCC {

Expand Down Expand Up @@ -35,8 +36,21 @@ struct TTransactionContext {
// Simulation mode parameters (0 = disabled)
int SimulateTransactionMs = 0;
int SimulateTransactionSelect1 = 0;

// User input for the current business transaction. Generated once and reused
// across retry attempts so a retry does not become a different txn.
std::shared_ptr<void> FixedInputs;
};

// Lazily generate and pin transaction inputs for the duration of retry attempts.
template <typename TInputs, typename TGen>
const TInputs& FixedTransactionInputs(TTransactionContext& context, TGen&& gen) {
if (!context.FixedInputs) {
context.FixedInputs = std::make_shared<TInputs>(std::forward<TGen>(gen)());
}
return *std::static_pointer_cast<TInputs>(context.FixedInputs);
}

struct TUserAbortedException : public std::runtime_error {
TUserAbortedException() : std::runtime_error("User aborted transaction (expected rollback)") {}
};
Expand Down