/***************************************************************************
* Copyright (C) 2011 by H-Store Project *
* Brown University *
* Massachusetts Institute of Technology *
* Yale University *
* *
* http://hstore.cs.brown.edu/ *
* *
* 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. *
***************************************************************************/
/* This file is part of VoltDB.
* Copyright (C) 2009 Vertica Systems Inc.
*
* 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 com.oltpbenchmark.benchmarks.seats;
import java.sql.Timestamp;
import java.sql.SQLException;
import java.util.*;
import org.apache.commons.collections15.map.ListOrderedMap;
import org.apache.log4j.Logger;
import com.oltpbenchmark.api.Procedure;
import com.oltpbenchmark.api.Procedure.UserAbortException;
import com.oltpbenchmark.api.TransactionType;
import com.oltpbenchmark.api.Worker;
import com.oltpbenchmark.benchmarks.seats.procedures.DeleteReservation;
import com.oltpbenchmark.benchmarks.seats.procedures.FindFlights;
import com.oltpbenchmark.benchmarks.seats.procedures.FindOpenSeats;
import com.oltpbenchmark.benchmarks.seats.procedures.NewReservation;
import com.oltpbenchmark.benchmarks.seats.procedures.UpdateCustomer;
import com.oltpbenchmark.benchmarks.seats.procedures.UpdateReservation;
import com.oltpbenchmark.benchmarks.seats.util.CustomerId;
import com.oltpbenchmark.benchmarks.seats.util.FlightId;
import com.oltpbenchmark.types.TransactionStatus;
import com.oltpbenchmark.util.RandomGenerator;
import com.oltpbenchmark.util.StringUtil;
public class SEATSWorker extends Worker {
private static final Logger LOG = Logger.getLogger(SEATSWorker.class);
/**
* Airline Benchmark Transactions
*/
private static enum Transaction {
DeleteReservation (DeleteReservation.class),
FindFlights (FindFlights.class),
FindOpenSeats (FindOpenSeats.class),
NewReservation (NewReservation.class),
UpdateCustomer (UpdateCustomer.class),
UpdateReservation (UpdateReservation.class);
private Transaction(Class<? extends Procedure> proc_class) {
this.proc_class = proc_class;
this.execName = proc_class.getSimpleName();
this.displayName = StringUtil.title(this.name().replace("_", " "));
}
public final Class<? extends Procedure> proc_class;
public final String displayName;
public final String execName;
protected static final Map<Integer, Transaction> idx_lookup = new HashMap<Integer, Transaction>();
protected static final Map<String, Transaction> name_lookup = new HashMap<String, Transaction>();
static {
for (Transaction vt : EnumSet.allOf(Transaction.class)) {
Transaction.idx_lookup.put(vt.ordinal(), vt);
Transaction.name_lookup.put(vt.name(), vt);
}
}
public static Transaction get(Integer idx) {
assert(idx >= 0);
return (Transaction.idx_lookup.get(idx));
}
public static Transaction get(String name) {
return (Transaction.name_lookup.get(name));
}
public String getDisplayName() {
return (this.displayName);
}
public String getExecName() {
return (this.execName);
}
}
// -----------------------------------------------------------------
// RESERVED SEAT BITMAPS
// -----------------------------------------------------------------
public enum CacheType {
PENDING_INSERTS (SEATSConstants.CACHE_LIMIT_PENDING_INSERTS),
PENDING_UPDATES (SEATSConstants.CACHE_LIMIT_PENDING_UPDATES),
PENDING_DELETES (SEATSConstants.CACHE_LIMIT_PENDING_DELETES),
;
private CacheType(int limit) {
this.limit = limit;
}
private final int limit;
}
protected final Map<CacheType, LinkedList<Reservation>> CACHE_RESERVATIONS = new HashMap<SEATSWorker.CacheType, LinkedList<Reservation>>();
{
for (CacheType ctype : CacheType.values()) {
CACHE_RESERVATIONS.put(ctype, new LinkedList<Reservation>());
} // FOR
}
protected final Map<CustomerId, Set<FlightId>> CACHE_CUSTOMER_BOOKED_FLIGHTS = new HashMap<CustomerId, Set<FlightId>>();
protected final Map<FlightId, BitSet> CACHE_BOOKED_SEATS = new HashMap<FlightId, BitSet>();
private static final BitSet FULL_FLIGHT_BITSET = new BitSet(SEATSConstants.FLIGHTS_NUM_SEATS);
static {
for (int i = 0; i < SEATSConstants.FLIGHTS_NUM_SEATS; i++)
FULL_FLIGHT_BITSET.set(i);
} // STATIC
protected BitSet getSeatsBitSet(FlightId flight_id) {
BitSet seats = CACHE_BOOKED_SEATS.get(flight_id);
if (seats == null) {
// synchronized (CACHE_BOOKED_SEATS) {
seats = CACHE_BOOKED_SEATS.get(flight_id);
if (seats == null) {
seats = new BitSet(SEATSConstants.FLIGHTS_NUM_SEATS);
CACHE_BOOKED_SEATS.put(flight_id, seats);
}
// } // SYNCH
}
return (seats);
}
/**
* Returns true if the given BitSet for a Flight has all of its seats reserved
* @param seats
* @return
*/
protected boolean isFlightFull(BitSet seats) {
assert(FULL_FLIGHT_BITSET.size() == seats.size());
return FULL_FLIGHT_BITSET.equals(seats);
}
/**
* Returns true if the given Customer already has a reservation booked on the target Flight
* @param customer_id
* @param flight_id
* @return
*/
protected boolean isCustomerBookedOnFlight(CustomerId customer_id, FlightId flight_id) {
Set<FlightId> flights = CACHE_CUSTOMER_BOOKED_FLIGHTS.get(customer_id);
return (flights != null && flights.contains(flight_id));
}
protected Set<FlightId> getCustomerBookedFlights(CustomerId customer_id) {
Set<FlightId> f_ids = CACHE_CUSTOMER_BOOKED_FLIGHTS.get(customer_id);
if (f_ids == null) {
f_ids = CACHE_CUSTOMER_BOOKED_FLIGHTS.get(customer_id);
if (f_ids == null) {
f_ids = new HashSet<FlightId>();
CACHE_CUSTOMER_BOOKED_FLIGHTS.put(customer_id, f_ids);
}
}
return (f_ids);
}
@Override
public String toString() {
Map<String, Object> m = new ListOrderedMap<String, Object>();
for (CacheType ctype : CACHE_RESERVATIONS.keySet()) {
m.put(ctype.name(), CACHE_RESERVATIONS.get(ctype).size());
} // FOR
m.put("CACHE_CUSTOMER_BOOKED_FLIGHTS", CACHE_CUSTOMER_BOOKED_FLIGHTS.size());
m.put("CACHE_BOOKED_SEATS", CACHE_BOOKED_SEATS.size());
m.put("PROFILE", this.profile);
return StringUtil.formatMaps(m);
}
// -----------------------------------------------------------------
// ADDITIONAL DATA MEMBERS
// -----------------------------------------------------------------
private final SEATSProfile profile;
private final RandomGenerator rng;
private final List<Reservation> tmp_reservations = new ArrayList<Reservation>();
/**
* When a customer looks for an open seat, they will then attempt to book that seat in
* a new reservation. Some of them will want to change their seats. This data structure
* represents a customer that is queued to change their seat.
*/
protected static class Reservation {
public final long id;
public final FlightId flight_id;
public final CustomerId customer_id;
public final int seatnum;
public Reservation(long id, FlightId flight_id, CustomerId customer_id, int seatnum) {
this.id = id;
this.flight_id = flight_id;
this.customer_id = customer_id;
this.seatnum = seatnum;
assert(this.seatnum >= 0) : "Invalid seat number\n" + this;
assert(this.seatnum < SEATSConstants.FLIGHTS_NUM_SEATS) : "Invalid seat number\n" + this;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Reservation) {
Reservation r = (Reservation)obj;
// Ignore id!
return (this.seatnum == r.seatnum &&
this.flight_id.equals(r.flight_id) &&
this.customer_id.equals(r.customer_id));
}
return (false);
}
@Override
public String toString() {
return String.format("{Id:%d / %s / %s / SeatNum:%d}",
this.id, this.flight_id, this.customer_id, this.seatnum);
}
} // END CLASS
// -----------------------------------------------------------------
// REQUIRED METHODS
// -----------------------------------------------------------------
public SEATSWorker(int id, SEATSBenchmark benchmark) {
super(benchmark, id);
this.rng = benchmark.getRandomGenerator();
this.profile = new SEATSProfile(benchmark, rng);
}
protected void initialize() {
try {
this.profile.loadProfile(this);
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
if (LOG.isTraceEnabled())
LOG.trace("Airport Max Customer Id:\n" + this.profile.airport_max_customer_id);
// Make sure we have the information we need in the BenchmarkProfile
String error_msg = null;
if (this.profile.getFlightIdCount() == 0) {
error_msg = "The benchmark profile does not have any flight ids.";
} else if (this.profile.getCustomerIdCount() == 0) {
error_msg = "The benchmark profile does not have any customer ids.";
} else if (this.profile.getFlightStartDate() == null) {
error_msg = "The benchmark profile does not have a valid flight start date.";
}
if (error_msg != null) throw new RuntimeException(error_msg);
// Fire off a FindOpenSeats so that we can prime ourselves
FindOpenSeats proc = this.getProcedure(FindOpenSeats.class);
try {
boolean ret = this.executeFindOpenSeats(proc);
assert(ret);
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
if (LOG.isDebugEnabled())
LOG.debug("Initialized SEATSWorker:\n" + this.toString());
}
@Override
protected TransactionStatus executeWork(TransactionType txnType) throws UserAbortException, SQLException {
Transaction txn = Transaction.get(txnType.getName());
assert(txn != null) : "Unexpected " + txnType;
// Get the Procedure handle
Procedure proc = this.getProcedure(txnType);
assert(proc != null) : String.format("Failed to get Procedure handle for %s.%s",
this.getBenchmarkModule().getBenchmarkName(), txnType);
if (LOG.isDebugEnabled())
LOG.debug("Attempting to execute " + proc);
boolean ret = false;
switch (txn) {
case DeleteReservation: {
ret = this.executeDeleteReservation((DeleteReservation)proc);
break;
}
case FindFlights: {
ret = this.executeFindFlights((FindFlights)proc);
break;
}
case FindOpenSeats: {
ret = this.executeFindOpenSeats((FindOpenSeats)proc);
break;
}
case NewReservation: {
ret = this.executeNewReservation((NewReservation)proc);
break;
}
case UpdateCustomer: {
ret = this.executeUpdateCustomer((UpdateCustomer)proc);
break;
}
case UpdateReservation: {
ret = this.executeUpdateReservation((UpdateReservation)proc);
break;
}
default:
assert(false) : "Unexpected transaction: " + txn;
} // SWITCH
if (ret == false) {
if (LOG.isDebugEnabled())
LOG.debug("Unable to execute " + proc + " right now");
return (TransactionStatus.RETRY_DIFFERENT);
}
if (ret && LOG.isDebugEnabled())
LOG.debug("Executed a new invocation of " + txn);
return (TransactionStatus.SUCCESS);
}
/**
* Take an existing Reservation that we know is legit and randomly decide to
* either queue it for a later update or delete transaction
* @param r
*/
protected void requeueReservation(Reservation r) {
CacheType ctype = null;
// Queue this motha trucka up for a deletin'
if (rng.nextBoolean()) {
ctype = CacheType.PENDING_DELETES;
} else {
ctype = CacheType.PENDING_UPDATES;
}
assert(ctype != null);
LinkedList<Reservation> cache = CACHE_RESERVATIONS.get(ctype);
assert(cache != null);
cache.add(r);
if (LOG.isDebugEnabled())
LOG.debug(String.format("Queued %s for %s [cache=%d]", r, ctype, cache.size()));
while (cache.size() > ctype.limit) {
cache.remove();
}
}
// -----------------------------------------------------------------
// DeleteReservation
// -----------------------------------------------------------------
private boolean executeDeleteReservation(DeleteReservation proc) throws SQLException {
// Pull off the first cached reservation and drop it on the cluster...
final Reservation r = CACHE_RESERVATIONS.get(CacheType.PENDING_DELETES).poll();
if (r == null) {
return (false);
}
int rand = rng.number(1, 100);
// Parameters
long f_id = r.flight_id.encode();
Long c_id = null;
String c_id_str = null;
String ff_c_id_str = null;
Long ff_al_id = null;
// Delete with the Customer's id as a string
if (rand <= SEATSConstants.PROB_DELETE_WITH_CUSTOMER_ID_STR) {
c_id_str = Long.toString(r.customer_id.encode());
}
// Delete using their FrequentFlyer information
else if (rand <= SEATSConstants.PROB_DELETE_WITH_CUSTOMER_ID_STR + SEATSConstants.PROB_DELETE_WITH_FREQUENTFLYER_ID_STR) {
ff_c_id_str = Long.toString(r.customer_id.encode());
ff_al_id = r.flight_id.getAirlineId();
}
// Delete using their Customer id
else {
c_id = r.customer_id.encode();
}
if (LOG.isTraceEnabled()) LOG.trace("Calling " + proc);
proc.run(conn, f_id, c_id, c_id_str, ff_c_id_str, ff_al_id);
conn.commit();
// We can remove this from our set of full flights because know that there is now a free seat
BitSet seats = getSeatsBitSet(r.flight_id);
seats.set(r.seatnum, false);
// And then put it up for a pending insert
if (rng.nextInt(100) < SEATSConstants.PROB_REQUEUE_DELETED_RESERVATION) {
CACHE_RESERVATIONS.get(CacheType.PENDING_INSERTS).add(r);
}
return (true);
}
// ----------------------------------------------------------------
// FindFlights
// ----------------------------------------------------------------
/**
* Execute one of the FindFlight transactions
* @param txn
* @throws SQLException
*/
private boolean executeFindFlights(FindFlights proc) throws SQLException {
long depart_airport_id;
long arrive_airport_id;
Timestamp start_date;
Timestamp stop_date;
// Select two random airport ids
if (rng.nextInt(100) < SEATSConstants.PROB_FIND_FLIGHTS_RANDOM_AIRPORTS) {
// Does it matter whether the one airport actually flies to the other one?
depart_airport_id = this.profile.getRandomAirportId();
arrive_airport_id = this.profile.getRandomOtherAirport(depart_airport_id);
// Select a random date from our upcoming dates
start_date = this.profile.getRandomUpcomingDate();
stop_date = new Timestamp(start_date.getTime() + (SEATSConstants.MILLISECONDS_PER_DAY * 2));
}
// Use an existing flight so that we guaranteed to get back results
else {
FlightId flight_id = this.profile.getRandomFlightId();
depart_airport_id = flight_id.getDepartAirportId();
arrive_airport_id = flight_id.getArriveAirportId();
Timestamp flightDate = flight_id.getDepartDate(this.profile.getFlightStartDate());
long range = Math.round(SEATSConstants.MILLISECONDS_PER_DAY * 0.5);
start_date = new Timestamp(flightDate.getTime() - range);
stop_date = new Timestamp(flightDate.getTime() + range);
if (LOG.isDebugEnabled())
LOG.debug(String.format("Using %s as look up in %s: %d / %s",
flight_id, proc, flight_id.encode(), flightDate));
}
// If distance is greater than zero, then we will also get flights from nearby airports
long distance = -1;
if (rng.nextInt(100) < SEATSConstants.PROB_FIND_FLIGHTS_NEARBY_AIRPORT) {
distance = SEATSConstants.DISTANCES[rng.nextInt(SEATSConstants.DISTANCES.length)];
}
if (LOG.isTraceEnabled()) LOG.trace("Calling " + proc);
List<Object[]> results = proc.run(conn,
depart_airport_id,
arrive_airport_id,
start_date,
stop_date,
distance);
conn.commit();
if (results.size() > 1) {
// Convert the data into a FlightIds that other transactions can use
int ctr = 0;
for (Object row[] : results) {
FlightId flight_id = new FlightId((Long)row[0]);
assert(flight_id != null);
boolean added = profile.addFlightId(flight_id);
if (added) ctr++;
} // WHILE
if (LOG.isDebugEnabled()) LOG.debug(String.format("Added %d out of %d FlightIds to local cache",
ctr, results.size()));
}
return (true);
}
// ----------------------------------------------------------------
// FindOpenSeats
// ----------------------------------------------------------------
/**
* Execute the FindOpenSeat procedure
* @throws SQLException
*/
private boolean executeFindOpenSeats(FindOpenSeats proc) throws SQLException {
final FlightId search_flight = this.profile.getRandomFlightId();
assert(search_flight != null);
Long airport_depart_id = search_flight.getDepartAirportId();
if (LOG.isTraceEnabled()) LOG.trace("Calling " + proc);
Object[][] results = proc.run(conn, search_flight.encode());
conn.commit();
int rowCount = results.length;
assert (rowCount <= SEATSConstants.FLIGHTS_NUM_SEATS) :
String.format("Unexpected %d open seats returned for %s", rowCount, search_flight);
// there is some tiny probability of an empty flight .. maybe 1/(20**150)
// if you hit this assert (with valid code), play the lottery!
if (rowCount == 0) return (true);
LinkedList<Reservation> cache = CACHE_RESERVATIONS.get(CacheType.PENDING_INSERTS);
assert(cache != null) : "Unexpected " + CacheType.PENDING_INSERTS;
// Store pending reservations in our queue for a later transaction
BitSet seats = getSeatsBitSet(search_flight);
tmp_reservations.clear();
for (Object row[] : results) {
if (row == null) continue; // || rng.nextInt(100) < 75) continue; // HACK
Integer seatnum = (Integer)row[1];
// We first try to get a CustomerId based at this departure airport
if (LOG.isTraceEnabled())
LOG.trace("Looking for a random customer to fly on " + search_flight);
CustomerId customer_id = profile.getRandomCustomerId(airport_depart_id);
// We will go for a random one if:
// (1) The Customer is already booked on this Flight
// (2) We already made a new Reservation just now for this Customer
int tries = SEATSConstants.FLIGHTS_NUM_SEATS;
while (tries-- > 0 && (customer_id == null)) { // || isCustomerBookedOnFlight(customer_id, flight_id))) {
customer_id = profile.getRandomCustomerId();
if (LOG.isTraceEnabled())
LOG.trace("RANDOM CUSTOMER: " + customer_id);
} // WHILE
assert(customer_id != null) :
String.format("Failed to find a unique Customer to reserve for seat #%d on %s", seatnum, search_flight);
Reservation r = new Reservation(profile.getNextReservationId(getId()),
search_flight,
customer_id,
seatnum.intValue());
seats.set(seatnum);
tmp_reservations.add(r);
if (LOG.isTraceEnabled())
LOG.trace("QUEUED INSERT: " + search_flight + " / " + search_flight.encode() + " -> " + customer_id);
} // WHILE
if (tmp_reservations.isEmpty() == false) {
Collections.shuffle(tmp_reservations);
cache.addAll(tmp_reservations);
while (cache.size() > SEATSConstants.CACHE_LIMIT_PENDING_INSERTS) {
cache.remove();
} // WHILE
if (LOG.isDebugEnabled())
LOG.debug(String.format("Stored %d pending inserts for %s [totalPendingInserts=%d]",
tmp_reservations.size(), search_flight, cache.size()));
}
return (true);
}
// ----------------------------------------------------------------
// NewReservation
// ----------------------------------------------------------------
private boolean executeNewReservation(NewReservation proc) throws SQLException {
Reservation reservation = null;
BitSet seats = null;
LinkedList<Reservation> cache = CACHE_RESERVATIONS.get(CacheType.PENDING_INSERTS);
assert(cache != null) : "Unexpected " + CacheType.PENDING_INSERTS;
if (LOG.isDebugEnabled())
LOG.debug(String.format("Attempting to get a new pending insert Reservation [totalPendingInserts=%d]",
cache.size()));
while (reservation == null) {
Reservation r = cache.poll();
if (r == null) {
if (LOG.isDebugEnabled())
LOG.warn("Unable to execute " + proc + " - No available reservations to insert");
break;
}
seats = getSeatsBitSet(r.flight_id);
if (isFlightFull(seats)) {
if (LOG.isDebugEnabled())
LOG.debug(String.format("%s is full", r.flight_id));
continue;
}
// PAVLO: Not sure why this is always coming back as reserved?
// else if (seats.get(r.seatnum)) {
// if (LOG.isDebugEnabled())
// LOG.debug(String.format("Seat #%d on %s is already booked", r.seatnum, r.flight_id));
// continue;
// }
else if (isCustomerBookedOnFlight(r.customer_id, r.flight_id)) {
if (LOG.isDebugEnabled())
LOG.debug(String.format("%s is already booked on %s", r.customer_id, r.flight_id));
continue;
}
reservation = r;
} // WHILE
if (reservation == null) {
if (LOG.isDebugEnabled())
LOG.warn("Failed to find a valid pending insert Reservation\n" + this.toString());
return (false);
}
// Generate a random price for now
double price = 2.0 * rng.number(SEATSConstants.RESERVATION_PRICE_MIN,
SEATSConstants.RESERVATION_PRICE_MAX);
// Generate random attributes
long attributes[] = new long[9];
for (int i = 0; i < attributes.length; i++) {
attributes[i] = rng.nextLong();
} // FOR
if (LOG.isTraceEnabled()) LOG.trace("Calling " + proc);
proc.run(conn, reservation.id,
reservation.customer_id.encode(),
reservation.flight_id.encode(),
reservation.seatnum,
price,
attributes);
conn.commit();
// Mark this seat as successfully reserved
seats.set(reservation.seatnum);
// Set it up so we can play with it later
this.requeueReservation(reservation);
return (true);
}
// ----------------------------------------------------------------
// UpdateCustomer
// ----------------------------------------------------------------
private boolean executeUpdateCustomer(UpdateCustomer proc) throws SQLException {
// Pick a random customer and then have at it!
CustomerId customer_id = this.profile.getRandomCustomerId();
Long c_id = null;
String c_id_str = null;
long attr0 = this.rng.nextLong();
long attr1 = this.rng.nextLong();
long update_ff = (rng.number(1, 100) <= SEATSConstants.PROB_UPDATE_FREQUENT_FLYER ? 1 : 0);
// Update with the Customer's id as a string
if (rng.nextInt(100) < SEATSConstants.PROB_UPDATE_WITH_CUSTOMER_ID_STR) {
c_id_str = Long.toString(customer_id.encode());
}
// Update using their Customer id
else {
c_id = customer_id.encode();
}
if (LOG.isTraceEnabled()) LOG.trace("Calling " + proc);
proc.run(conn, c_id, c_id_str, update_ff, attr0, attr1);
conn.commit();
return (true);
}
// ----------------------------------------------------------------
// UpdateReservation
// ----------------------------------------------------------------
private boolean executeUpdateReservation(UpdateReservation proc) throws SQLException {
LinkedList<Reservation> cache = CACHE_RESERVATIONS.get(CacheType.PENDING_UPDATES);
assert(cache != null) : "Unexpected " + CacheType.PENDING_UPDATES;
if (LOG.isTraceEnabled())
LOG.trace("Let's look for a Reservation that we can update");
// Pull off the first pending seat change and throw that ma at the server
Reservation r = null;
try {
r = cache.poll();
} catch (Throwable ex) {
// Nothing
}
if (r == null) {
if (LOG.isDebugEnabled())
LOG.warn(String.format("Failed to find Reservation to update [cache=%d]", cache.size()));
return (false);
}
if (LOG.isTraceEnabled())
LOG.trace("Ok let's try to update " + r);
long value = rng.number(1, 1 << 20);
long attribute_idx = rng.nextInt(UpdateReservation.NUM_UPDATES);
long seatnum = rng.number(0, SEATSConstants.FLIGHTS_NUM_SEATS-1);
if (LOG.isTraceEnabled()) LOG.trace("Calling " + proc);
proc.run(conn, r.id,
r.flight_id.encode(),
r.customer_id.encode(),
seatnum,
attribute_idx,
value);
conn.commit();
SEATSWorker.this.requeueReservation(r);
return (true);
}
}