Package edu.brown.benchmark.auctionmark

Source Code of edu.brown.benchmark.auctionmark.AuctionMarkClient$GetUserInfoCallback

/***************************************************************************
*  Copyright (C) 2010 by H-Store Project                                  *
*  Brown University                                                       *
*  Massachusetts Institute of Technology                                  *
*  Yale University                                                        *
*                                                                         *
*  Andy Pavlo (pavlo@cs.brown.edu)                                        *
*  http://www.cs.brown.edu/~pavlo/                                        *
*                                                                         *
*  Visawee Angkanawaraphan (visawee@cs.brown.edu)                         *
*  http://www.cs.brown.edu/~visawee/                                      *
*                                                                         *
*  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.auctionmark;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.voltdb.VoltTable;
import org.voltdb.VoltType;
import org.voltdb.client.Client;
import org.voltdb.client.ClientResponse;
import org.voltdb.client.NoConnectionsException;
import org.voltdb.client.ProcedureCallback;
import org.voltdb.types.TimestampType;

import edu.brown.api.BenchmarkComponent;
import edu.brown.benchmark.auctionmark.AuctionMarkConstants.ItemStatus;
import edu.brown.benchmark.auctionmark.util.GlobalAttributeValueId;
import edu.brown.benchmark.auctionmark.util.ItemId;
import edu.brown.benchmark.auctionmark.util.ItemInfo;
import edu.brown.benchmark.auctionmark.util.UserId;
import edu.brown.hstore.Hstoreservice.Status;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.rand.AbstractRandomGenerator;
import edu.brown.rand.DefaultRandomGenerator;
import edu.brown.statistics.ObjectHistogram;
import edu.brown.utils.CompositeId;
import edu.brown.utils.StringUtil;

public class AuctionMarkClient extends BenchmarkComponent {
    private static final Logger LOG = Logger.getLogger(AuctionMarkLoader.class);
    private static final LoggerBoolean debug = new LoggerBoolean();
    private static final LoggerBoolean trace = new LoggerBoolean();
    static {
        LoggerUtil.attachObserver(LOG, debug, trace);
    }

    protected final AuctionMarkProfile profile;
   
    /**
     * TODO
     */
    private final Map<UserId, Integer> seller_item_cnt = new HashMap<UserId, Integer>();

    /**
     * TODO
     */
    private final List<long[]> pending_commentResponse = Collections.synchronizedList(new ArrayList<long[]>());
   
    // --------------------------------------------------------------------
    // TXN PARAMETER GENERATOR
    // --------------------------------------------------------------------
    public interface AuctionMarkParamGenerator {
        /**
         * Returns true if the client will be able to successfully generate a new transaction call
         * The client passes in the current BenchmarkProfile handle and an optional VoltTable. This allows
         * you to invoke one txn using the output of a previously run txn.
         * Note that this is not thread safe, so you'll need to combine the call to this with generate()
         * in a single synchronization block.
         * @param client
         * @return
         */
        public boolean canGenerateParam(AuctionMarkClient client);
        /**
         * Generate the parameters array
         * Any elements that are CompositeIds will automatically be encoded before being
         * shipped off to the H-Store cluster
         * @param client
         * @return
         */
        public Object[] generateParams(AuctionMarkClient client);
    }
   
    // --------------------------------------------------------------------
    // BENCHMARK TRANSACTIONS
    // --------------------------------------------------------------------
    public enum Transaction {
        // ====================================================================
        // CLOSE_AUCTIONS
        // ====================================================================
        CLOSE_AUCTIONS(AuctionMarkConstants.FREQUENCY_CLOSE_AUCTIONS, new AuctionMarkParamGenerator() {
            @Override
            public Object[] generateParams(AuctionMarkClient client) {
                return new Object[] { client.getTimestampParameterArray(),
                                      client.profile.getLastCloseAuctionsTime(),
                                      client.profile.updateAndGetLastCloseAuctionsTime() };
            }
            @Override
            public boolean canGenerateParam(AuctionMarkClient client) {
                if (AuctionMarkConstants.ENABLE_CLOSE_AUCTIONS && client.getClientId() == 0) {
                    // If we've never checked before, then we'll want to do that now
                    if (client.profile.hasLastCloseAuctionsTime() == false) return (true);

                    // Otherwise check whether enough time has passed since the last time we checked
                    TimestampType lastCheckWinningBidTime = client.profile.getLastCloseAuctionsTime();
                    TimestampType currentTime = client.profile.getCurrentTime();
                    long time_elapsed = Math.round((currentTime.getTime() - lastCheckWinningBidTime.getTime()) / 1000.0);
                    if (debug.val) LOG.debug(String.format("%s [start=%s, current=%s, elapsed=%d]", Transaction.CLOSE_AUCTIONS, client.profile.getBenchmarkStartTime(), currentTime, time_elapsed));
                    if (time_elapsed > AuctionMarkConstants.INTERVAL_CLOSE_AUCTIONS) return (true);
                }
                return (false);
            }
        }),
        // ====================================================================
        // GET_ITEM
        // ====================================================================
        GET_ITEM(AuctionMarkConstants.FREQUENCY_GET_ITEM, new AuctionMarkParamGenerator() {
            @Override
            public Object[] generateParams(AuctionMarkClient client) {
                ItemInfo itemInfo = client.profile.getRandomAvailableItemId();
                return new Object[] { client.getTimestampParameterArray(),
                                      itemInfo.itemId, itemInfo.getSellerId() };
            }

            @Override
            public boolean canGenerateParam(AuctionMarkClient client) {
                return (client.profile.getAvailableItemsCount() > 0);
            }
        }),
        // ====================================================================
        // GET_USER_INFO
        // ====================================================================
        GET_USER_INFO(AuctionMarkConstants.FREQUENCY_GET_USER_INFO, new AuctionMarkParamGenerator() {
            @Override
            public Object[] generateParams(AuctionMarkClient client) {
                UserId userId = client.profile.getRandomBuyerId();
                int rand;
               
                // USER_FEEDBACK records
                rand = client.profile.rng.number(0, 100);
                long get_feedback = (rand <= AuctionMarkConstants.PROB_GETUSERINFO_INCLUDE_FEEDBACK ? 1 : VoltType.NULL_BIGINT);

                // ITEM_COMMENT records
                rand = client.profile.rng.number(0, 100);
                long get_comments = (rand <= AuctionMarkConstants.PROB_GETUSERINFO_INCLUDE_COMMENTS ? 1 : VoltType.NULL_BIGINT);
               
                // Seller ITEM records
                rand = 100; // client.profile.rng.number(0, 100);
                long get_seller_items = (rand <= AuctionMarkConstants.PROB_GETUSERINFO_INCLUDE_SELLER_ITEMS ? 1 : VoltType.NULL_BIGINT);

                // Buyer ITEM records
                rand = 100; // client.profile.rng.number(0, 100);
                long get_buyer_items = (rand <= AuctionMarkConstants.PROB_GETUSERINFO_INCLUDE_BUYER_ITEMS ? 1 : VoltType.NULL_BIGINT);
               
                // USER_WATCH records
                rand = 100; // client.profile.rng.number(0, 100);
                long get_watched_items = (rand <= AuctionMarkConstants.PROB_GETUSERINFO_INCLUDE_WATCHED_ITEMS ? 1 : VoltType.NULL_BIGINT);
               
                return new Object[] { client.getTimestampParameterArray(),
                                      userId,
                                      get_feedback, get_comments,
                                      get_seller_items, get_buyer_items, get_watched_items };
            }
            @Override
            public boolean canGenerateParam(AuctionMarkClient client) {
                return (true);
            }
        }),
        // ====================================================================
        // NEW_BID
        // ====================================================================
        NEW_BID(AuctionMarkConstants.FREQUENCY_NEW_BID, new AuctionMarkParamGenerator() {
            @Override
            public Object[] generateParams(AuctionMarkClient client) {
               
                ItemInfo itemInfo = null;
                UserId sellerId;
                UserId buyerId;
                double bid;
                double maxBid;
               
                boolean has_available = (client.profile.getAvailableItemsCount() > 0);
                boolean has_ending = (client.profile.getEndingSoonItemsCount() > 0);
                boolean has_waiting = (client.profile.getWaitForPurchaseItemsCount() > 0);
                boolean has_completed = (client.profile.getCompleteItemsCount() > 0);
               
                // Some NEW_BIDs will be for items that have already ended.
                // This will simulate somebody trying to bid at the very end but failing
                if ((has_waiting || has_completed) &&
                    (client.profile.rng.number(1, 100) <= AuctionMarkConstants.PROB_NEWBID_CLOSED_ITEM || has_available == false)) {
                    if (has_waiting) {
                        itemInfo = client.profile.getRandomWaitForPurchaseItem();
                        assert(itemInfo != null) : "Failed to get WaitForPurchase itemInfo [" + client.profile.getWaitForPurchaseItemsCount() + "]";
                    } else {
                        itemInfo = client.profile.getRandomCompleteItem();
                        assert(itemInfo != null) : "Failed to get Completed itemInfo [" + client.profile.getCompleteItemsCount() + "]";
                    }
                    sellerId = itemInfo.getSellerId();
                    buyerId = client.profile.getRandomBuyerId(sellerId);
                   
                    // The bid/maxBid do not matter because they won't be able to actually
                    // update the auction
                    bid = client.profile.rng.nextDouble();
                    maxBid = bid + 100;
                }
               
                // Otherwise we want to generate information for a real bid
                else {
                    assert(has_available || has_ending);
                    // 50% of NEW_BIDS will be for items that are ending soon
                    if ((has_ending && client.profile.rng.number(1, 100) <= AuctionMarkConstants.PROB_NEWBID_CLOSED_ITEM) || has_available == false) {
                        itemInfo = client.profile.getRandomEndingSoonItem(true);
                    }
                    if (itemInfo == null) {
                        itemInfo = client.profile.getRandomAvailableItem(true);
                    }
                    if (itemInfo == null) {
                        itemInfo = client.profile.getRandomItem();
                    }
                   
                    sellerId = itemInfo.getSellerId();
                    buyerId = client.profile.getRandomBuyerId(sellerId);
                   
                    double currentPrice = itemInfo.getCurrentPrice();
                    bid = client.profile.rng.fixedPoint(2, currentPrice, currentPrice * (1 + (AuctionMarkConstants.ITEM_BID_PERCENT_STEP / 2)));
                    maxBid = client.profile.rng.fixedPoint(2, bid, (bid * (1 + (AuctionMarkConstants.ITEM_BID_PERCENT_STEP / 2))));
                }

                return new Object[] { client.getTimestampParameterArray(),
                                      itemInfo.itemId, sellerId, buyerId, maxBid, itemInfo.endDate };
            }
            @Override
            public boolean canGenerateParam(AuctionMarkClient client) {
                return (client.profile.getAllItemsCount() > 0);
            }
        }),
        // ====================================================================
        // NEW_COMMENT
        // ====================================================================
        NEW_COMMENT(AuctionMarkConstants.FREQUENCY_NEW_COMMENT, new AuctionMarkParamGenerator() {
            @Override
            public Object[] generateParams(AuctionMarkClient client) {
                ItemInfo itemInfo = client.profile.getRandomCompleteItem();
                UserId sellerId = itemInfo.getSellerId();
                UserId buyerId = client.profile.getRandomBuyerId(sellerId);
                String question = client.profile.rng.astring(10, 128);
                return new Object[] { client.getTimestampParameterArray(),
                                      itemInfo.itemId, sellerId, buyerId, question };
            }
            @Override
            public boolean canGenerateParam(AuctionMarkClient client) {
                return (client.profile.getCompleteItemsCount() > 0);
            }
        }),
        // ====================================================================
        // NEW_COMMENT_RESPONSE
        // ====================================================================
        NEW_COMMENT_RESPONSE(AuctionMarkConstants.FREQUENCY_NEW_COMMENT_RESPONSE, new AuctionMarkParamGenerator() {
            @Override
            public Object[] generateParams(AuctionMarkClient client) {
                Collections.shuffle(client.pending_commentResponse, client.profile.rng);
                long row[] = client.pending_commentResponse.remove(0);
                assert(row != null);
               
                long commentId = row[0];
                ItemId itemId = new ItemId(row[1]);
                UserId sellerId = itemId.getSellerId();
                String response = client.profile.rng.astring(10, 128);

                return new Object[] { client.getTimestampParameterArray(),
                                      itemId, sellerId, commentId, response };
            }
            @Override
            public boolean canGenerateParam(AuctionMarkClient client) {
                return (client.pending_commentResponse.isEmpty() == false);
            }
        }),
        // ====================================================================
        // NEW_FEEDBACK
        // ====================================================================
        NEW_FEEDBACK(AuctionMarkConstants.FREQUENCY_NEW_FEEDBACK, new AuctionMarkParamGenerator() {
            @Override
            public Object[] generateParams(AuctionMarkClient client) {
                ItemInfo itemInfo = client.profile.getRandomCompleteItem();
                UserId sellerId = itemInfo.getSellerId();
                UserId buyerId = client.profile.getRandomBuyerId(sellerId);
                long rating = (long) client.profile.rng.number(-1, 1);
                String feedback = client.profile.rng.astring(10, 80);
                return new Object[] { client.getTimestampParameterArray(),
                                      itemInfo.itemId, sellerId, buyerId, rating, feedback };
            }
            @Override
            public boolean canGenerateParam(AuctionMarkClient client) {
                return (client.profile.getCompleteItemsCount() > 0);
            }
        }),
        // ====================================================================
        // NEW_ITEM
        // ====================================================================
        NEW_ITEM(AuctionMarkConstants.FREQUENCY_NEW_ITEM, new AuctionMarkParamGenerator() {
            @Override
            public Object[] generateParams(AuctionMarkClient client) {
                UserId sellerId = client.profile.getRandomSellerId(client.getClientId());
                ItemId itemId = client.getNextItemId(sellerId);

                String name = client.profile.rng.astring(6, 32);
                String description = client.profile.rng.astring(50, 255);
                long categoryId = client.profile.getRandomCategoryId();

                Double initial_price = (double) client.profile.randomInitialPrice.nextInt();
                String attributes = client.profile.rng.astring(50, 255);

                int numAttributes = client.profile.randomNumAttributes.nextInt();
                List<GlobalAttributeValueId> gavList = new ArrayList<GlobalAttributeValueId>(numAttributes);
                for (int i = 0; i < numAttributes; i++) {
                    GlobalAttributeValueId gav_id = client.profile.getRandomGlobalAttributeValue();
                    if (!gavList.contains(gav_id)) gavList.add(gav_id);
                } // FOR

                long[] gag_ids = new long[gavList.size()];
                long[] gav_ids = new long[gavList.size()];
                for (int i = 0, cnt = gag_ids.length; i < cnt; i++) {
                    GlobalAttributeValueId gav_id = gavList.get(i);
                    gag_ids[i] = gav_id.getGlobalAttributeGroup().encode();
                    gav_ids[i] = gav_id.encode();
                } // FOR

                int numImages = client.profile.randomNumImages.nextInt();
                String[] images = new String[numImages];
                for (int i = 0; i < numImages; i++) {
                    images[i] = client.profile.rng.astring(20, 100);
                } // FOR

                long duration = client.profile.randomDuration.nextInt();

                return new Object[] { client.getTimestampParameterArray(),
                                      itemId, sellerId, categoryId,
                                      name, description, duration, initial_price, attributes,
                                      gag_ids, gav_ids, images };
            }
            @Override
            public boolean canGenerateParam(AuctionMarkClient client) {
                return (true);
            }
        }),
        // ====================================================================
        // NEW_PURCHASE
        // ====================================================================
        NEW_PURCHASE(AuctionMarkConstants.FREQUENCY_NEW_PURCHASE, new AuctionMarkParamGenerator() {
            @Override
            public Object[] generateParams(AuctionMarkClient client) {
                ItemInfo itemInfo = client.profile.getRandomWaitForPurchaseItem();
                UserId sellerId = itemInfo.getSellerId();
                double buyer_credit = 0d;
               
                // Whether the buyer will not have enough money
                if (itemInfo.hasCurrentPrice()) {
                    if (client.profile.rng.number(1, 100) < AuctionMarkConstants.PROB_NEW_PURCHASE_NOT_ENOUGH_MONEY) {
                        buyer_credit = -1 * itemInfo.getCurrentPrice();
                    } else {
                        buyer_credit = itemInfo.getCurrentPrice();
                        client.profile.removeWaitForPurchaseItem(itemInfo);
                    }
                }
                return new Object[] { client.getTimestampParameterArray(),
                                      itemInfo.itemId, sellerId, buyer_credit };
            }
            @Override
            public boolean canGenerateParam(AuctionMarkClient client) {
                return (client.profile.getWaitForPurchaseItemsCount() > 0);
            }
        }),
        // ====================================================================
        // UPDATE_ITEM
        // ====================================================================
        UPDATE_ITEM(AuctionMarkConstants.FREQUENCY_UPDATE_ITEM, new AuctionMarkParamGenerator() {
            @Override
            public Object[] generateParams(AuctionMarkClient client) {
                ItemInfo itemInfo = client.profile.getRandomAvailableItemId();
                UserId sellerId = itemInfo.getSellerId();
                String description = client.profile.rng.astring(50, 255);
               
                long delete_attribute = VoltType.NULL_BIGINT;
                long add_attribute[] = {
                    VoltType.NULL_BIGINT,
                    VoltType.NULL_BIGINT
                };
               
                // Delete ITEM_ATTRIBUTE
                if (client.profile.rng.number(1, 100) < AuctionMarkConstants.PROB_UPDATEITEM_DELETE_ATTRIBUTE) {
                    delete_attribute = 1;
                }
                // Add ITEM_ATTRIBUTE
                else if (client.profile.rng.number(1, 100) < AuctionMarkConstants.PROB_UPDATEITEM_ADD_ATTRIBUTE) {
                    GlobalAttributeValueId gav_id = client.profile.getRandomGlobalAttributeValue();
                    assert(gav_id != null);
                    add_attribute[0] = gav_id.getGlobalAttributeGroup().encode();
                    add_attribute[1] = gav_id.encode();
                }
               
                return new Object[] { client.getTimestampParameterArray(),
                                      itemInfo.itemId, sellerId, description,
                                      delete_attribute, add_attribute };
            }
            @Override
            public boolean canGenerateParam(AuctionMarkClient client) {
                return (client.profile.getAvailableItemsCount() > 0);
            }
        }),
        ;
       
        /**
         * Constructor
         * @param weight The execution frequency weight for this txn
         * @param generator
         */
        private Transaction(int weight, AuctionMarkParamGenerator generator) {
            this.default_weight = weight;
            this.displayName = StringUtil.title(this.name().replace("_", " "));
            this.callName = this.displayName.replace(" ", "");
            this.generator = generator;
        }

        public final int default_weight;
        public final String displayName;
        public final String callName;
        public final AuctionMarkParamGenerator generator;
       
        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().toLowerCase().intern(), 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.toLowerCase().intern()));
        }
       
        public int getDefaultWeight() {
            return (this.default_weight);
        }
       
        public String getDisplayName() {
            return (this.displayName);
        }
       
        public String getCallName() {
            return (this.callName);
        }
       
        /**
         * This will return true if we can call a new transaction for this procedure
         * A txn can be called if we can generate all of the parameters we need
         * @return
         */
        public boolean canExecute(AuctionMarkClient client) {
            if (debug.val) LOG.debug("Checking whether we can execute " + this + " now");
            return this.generator.canGenerateParam(client);
        }
       
        /**
         * Given a BenchmarkProfile object, call the AuctionMarkParamGenerator object for a given
         * transaction type to generate a set of parameters for a new txn invocation
         * @param profile
         * @return
         */
        public Object[] generateParams(AuctionMarkClient client) {
            Object vals[] = this.generator.generateParams(client);
            // Automatically encode any CompositeIds
            for (int i = 0; i < vals.length; i++) {
                if (vals[i] instanceof CompositeId) vals[i] = ((CompositeId)vals[i]).encode();
            } // FOR
            return (vals);
        }
    }

    // -----------------------------------------------------------------
    // ADDITIONAL DATA MEMBERS
    // -----------------------------------------------------------------
   
    private final Map<Transaction, Integer> weights = new HashMap<Transaction, Integer>();
    private final Transaction xacts[] = new Transaction[100];
   
    // -----------------------------------------------------------------
    // REQUIRED METHODS
    // -----------------------------------------------------------------

    public static void main(String args[]) {
        edu.brown.api.BenchmarkComponent.main(AuctionMarkClient.class, args, false);
    }

    /**
     * Constructor
     * @param args
     */
    public AuctionMarkClient(String[] args) {
        super(args);
       
        int seed = 0;
        String randGenClassName = DefaultRandomGenerator.class.getName();
        String randGenProfilePath = null;
        Integer temporal_window = null;
        Integer temporal_total = null;
       
        for (String key : m_extraParams.keySet()) {
            String value = m_extraParams.get(key);

            // Random Generator Seed
            if (key.equalsIgnoreCase("RANDOMSEED")) {
                seed = Integer.parseInt(value);
            }
            // Random Generator Class
            else if (key.equalsIgnoreCase("RANDOMGENERATOR")) {
                randGenClassName = value;
            }
            // Random Generator Profile File
            else if (key.equalsIgnoreCase("RANDOMPROFILE")) {
                randGenProfilePath = value;
            }
            // Temporal Skew
            else if (key.equalsIgnoreCase("TEMPORALWINDOW")) {
                assert(m_extraParams.containsKey("TEMPORALTOTAL")) : "Missing TEMPORALTOTAL parameter";
                temporal_window = Integer.valueOf(m_extraParams.get("TEMPORALWINDOW"));
                temporal_total = Integer.valueOf(m_extraParams.get("TEMPORALTOTAL"));
            }
        } // FOR
       
        // Random Generator
        AbstractRandomGenerator rng = null;
        try {
            rng = AbstractRandomGenerator.factory(randGenClassName, seed);
            if (randGenProfilePath != null) rng.loadProfile(randGenProfilePath);
        } catch (Exception ex) {
            ex.printStackTrace();
            System.exit(1);
        }
       
        // BenchmarkProfile
        profile = new AuctionMarkProfile(rng, getNumClients());
        profile.loadProfile(this);
       
        // Initialize Default Weights
        for (Transaction t : Transaction.values()) {
            Integer weight = this.getTransactionWeight(t.callName);
            this.weights.put(t, (weight != null ? weight : t.getDefaultWeight()));
        } // FOR

        // Create xact lookup array
        int total = 0;
        for (Transaction t : Transaction.values()) {
            for (int i = 0, cnt = this.weights.get(t); i < cnt; i++) {
                if (trace.val)
                    LOG.trace("xact " + total + " = " + t + ":" + t.getCallName());
                this.xacts[total++] = t;
            } // FOR
        } // FOR
        assert(total == xacts.length) : "The total weight for the transactions is " + total + ". It needs to be " + xacts.length;
    }

    @Override
    public String[] getTransactionDisplayNames() {
        String names[] = new String[Transaction.values().length];
        for (Transaction t : Transaction.values()) {
            names[t.ordinal()] = t.getDisplayName();
        }
        return names;
    }
   
    @Override
    public void runLoop() {
        final Client client = this.getClientHandle();
       
        // Execute Transactions
        try {
            while (true) {
                runOnce();
                client.backpressureBarrier();
            } // WHILE
        } catch (InterruptedException e) {
            e.printStackTrace();
            return;
        } catch (NoConnectionsException e) {
            /*
             * Client has no clean mechanism for terminating with the DB.
             */
            return;
        } catch (IOException e) {
            /*
             * At shutdown an IOException is thrown for every connection to
             * the DB that is lost Ignore the exception here in order to not
             * get spammed, but will miss lost connections at runtime
             */
        }
    }
   
    @Override
    public void tickCallback(int counter) {
        super.tickCallback(counter);
        profile.tick();
    }
   
    @Override
    protected boolean runOnce() throws IOException {
        // We need to subtract the different between this and the profile's start time,
        // since that accounts for the time gap between when the loader started and when the client start.
        // Otherwise, all of our cache date will be out dated if it took a really long time
        // to load everything up. Again, in order to keep things in synch, we only want to
        // set this on the first call to runOnce(). This will account for start a bunch of
        // clients on multiple nodes but then having to wait until they're all up and running
        // before starting the actual benchmark run.
        if (profile.hasClientStartTime() == false) profile.setAndGetClientStartTime();
       
        Transaction txn = null;
        Object[] params = null;

        // Always update the current timestamp
        profile.updateAndGetCurrentTime();

        // Find the next txn and its parameters that we will run. We want to wrap this
        // around a synchronization block so that nobody comes in and takes the parameters
        // from us before we actually run it
        int safety = 1000;
        while (safety-- > 0) {
            Transaction tempTxn = null;
           
            // Always check if we need to want to run CLOSE_AUCTIONS
            // We only do this from the first client
            if (Transaction.CLOSE_AUCTIONS.canExecute(this)) {
                tempTxn = Transaction.CLOSE_AUCTIONS;
            }
            // Otherwise randomly pick a transaction based on their distribution weights
            else {
                int idx = profile.rng.number(0, this.xacts.length - 1);
                if (trace.val) {
                    LOG.trace("idx = " + idx);
                    LOG.trace("random txn = " + this.xacts[idx].getDisplayName());
                }
                assert (idx >= 0);
                assert (idx < this.xacts.length);
                tempTxn = this.xacts[idx];
            }

            // Only execute this txn if it is ready
            // Example: NewBid can only be executed if there are item_ids retrieved by an earlier call by GetItem
            if (tempTxn.canExecute(this)) {
                txn = tempTxn;
                if (trace.val) LOG.trace("CAN EXECUTE: " + txn);
                try {
                    params = txn.generateParams(this);
                } catch (Throwable ex) {
                    throw new RuntimeException("Failed to generate parameters for " + txn, ex);
                }
                break;
            }
        } // WHILE
        assert (txn != null);
       
        if (params == null) {
            LOG.warn("Unable to execute " + txn + " because the parameters were null?");
            return (false);
        } else if (debug.val) {
            LOG.info("Executing new invocation of transaction " + txn);
        }
       
        BaseCallback callback = null;
        switch (txn) {
            case CLOSE_AUCTIONS:
                callback = new CloseAuctionsCallback(params);
                break;
            case GET_ITEM:
                callback = new GetItemCallback(params);
                break;
            case GET_USER_INFO:
                callback = new GetUserInfoCallback(params);
                break;
            case NEW_COMMENT:
                callback = new NewCommentCallback(params);
                break;
            case NEW_ITEM:
                callback = new NewItemCallback(params);
                break;
            case NEW_PURCHASE:
                callback = new NewPurchaseCallback(params);
                break;
            default:
                callback = new NullCallback(txn, params);
        } // SWITCH
        this.getClientHandle().callProcedure(callback, txn.getCallName(), params);
        return (true);
    }
   
    /**********************************************************************************************
     * Base Callback
     **********************************************************************************************/
    protected abstract class BaseCallback implements ProcedureCallback {
        final Transaction txn;
        final Object params[];
        final ObjectHistogram<ItemStatus> updated = new ObjectHistogram<ItemStatus>();
       
        public BaseCallback(Transaction txn, Object params[]) {
            this.txn = txn;
            this.params = params;
        }
       
        public abstract void process(VoltTable results[]);
       
        @Override
        public void clientCallback(ClientResponse clientResponse) {
            if (trace.val) LOG.trace("clientCallback(cid = " + getClientId() + "):: txn = " + txn.getDisplayName());
            incrementTransactionCounter(clientResponse, this.txn.ordinal());
            VoltTable[] results = clientResponse.getResults();
            if (clientResponse.getStatus() == Status.OK) {
                try {
                    this.process(results);
                } catch (Throwable ex) {
                    LOG.error("PARAMS: " + Arrays.toString(this.params));
                    for (int i = 0; i < results.length; i++) {
                        LOG.info(String.format("[%02d] RESULT\n%s", i, results[i]));
                    } // FOR
                    throw new RuntimeException("Failed to process results for " + this.txn, ex);
                }
                   
            } else {
                if (debug.val) LOG.debug(String.format("%s: %s", this.txn, clientResponse.getStatusString()), clientResponse.getException());
            }
        }
        /**
         * For the given VoltTable that contains ITEM records, process the current
         * row of that table and update the benchmark profile based on item information
         * stored in that row.
         * @param vt
         * @return
         */
        public ItemId processItemRecord(VoltTable vt) {
            ItemId itemId = new ItemId(vt.getLong("i_id"));
            TimestampType endDate = vt.getTimestampAsTimestamp("i_end_date");
            short numBids = (short)vt.getLong("i_num_bids");
            double currentPrice = vt.getDouble("i_current_price");
            ItemInfo itemInfo = new ItemInfo(itemId, currentPrice, endDate, numBids);
            if (vt.hasColumn("ip_id")) itemInfo.status = ItemStatus.CLOSED;
            if (vt.hasColumn("i_status")) itemInfo.status = ItemStatus.get(vt.getLong("i_status"));
           
            UserId sellerId = new UserId(vt.getLong("i_u_id"));
            assert (itemId.getSellerId().equals(sellerId));
           
            ItemStatus qtype = profile.addItemToProperQueue(itemInfo, false);
            this.updated.put(qtype);

            return (itemId);
        }
        @Override
        public String toString() {
            String cnts[] = new String[ItemStatus.values().length];
            for (ItemStatus qtype : ItemStatus.values()) {
                cnts[qtype.ordinal()] = String.format("%s=+%d", qtype, updated.get(qtype, 0));
            }
            return String.format("%s :: %s", this.txn, StringUtil.join(", ", cnts));
        }
    } // END CLASS
   
    /**********************************************************************************************
     * NULL Callback
     **********************************************************************************************/
    protected class NullCallback extends BaseCallback {
        public NullCallback(Transaction txn, Object params[]) {
            super(txn, params);
        }
        @Override
        public void process(VoltTable[] results) {
            // Nothing to do...
        }
    } // END CLASS
   
    /**********************************************************************************************
     * CLOSE_AUCTIONS Callback
     **********************************************************************************************/
    protected class CloseAuctionsCallback extends BaseCallback {
        public CloseAuctionsCallback(Object params[]) {
            super(Transaction.CLOSE_AUCTIONS, params);
        }
        @Override
        public void process(VoltTable[] results) {
            assert (null != results && results.length > 0);
            while (results[0].advanceRow()) {
                ItemId itemId = this.processItemRecord(results[0]);
                assert(itemId != null);
            } // WHILE
            if (debug.val) LOG.debug(super.toString());
            profile.updateItemQueues();
        }
    } // END CLASS
   
    /**********************************************************************************************
     * NEW_COMMENT Callback
     **********************************************************************************************/
    protected class NewCommentCallback extends BaseCallback {
        public NewCommentCallback(Object params[]) {
            super(Transaction.NEW_COMMENT, params);
        }
        @Override
        public void process(VoltTable[] results) {
            assert(results.length == 1);
            while (results[0].advanceRow()) {
                long vals[] = {
                    results[0].getLong("ic_id"),
                    results[0].getLong("ic_i_id"),
                    results[0].getLong("ic_u_id")
                };
                pending_commentResponse.add(vals);
            } // WHILE
        }
    } // END CLASS
       
    /**********************************************************************************************
     * GET_ITEM Callback
     **********************************************************************************************/
    protected class GetItemCallback extends BaseCallback {
        public GetItemCallback(Object params[]) {
            super(Transaction.GET_ITEM, params);
        }
        @Override
        public void process(VoltTable[] results) {
            assert (null != results && results.length > 0);
            while (results[0].advanceRow()) {
                ItemId itemId = this.processItemRecord(results[0]);
                assert(itemId != null);
            } // WHILE
            if (debug.val) LOG.debug(super.toString());
        }
    } // END CLASS
   
    /**********************************************************************************************
     * GET_USER_INFO Callback
     **********************************************************************************************/
    protected class GetUserInfoCallback extends BaseCallback {
        final boolean expect_user;
        final boolean expect_feedback;
        final boolean expect_comments;
        final boolean expect_seller;
        final boolean expect_buyer;
        final boolean expect_watched;
       
        public GetUserInfoCallback(Object params[]) {
            super(Transaction.GET_USER_INFO, params);
           
            int idx = 2;
            this.expect_user     = true;
            this.expect_feedback = ((Long)params[idx++] != VoltType.NULL_BIGINT);
            this.expect_comments = ((Long)params[idx++] != VoltType.NULL_BIGINT);
            this.expect_seller   = ((Long)params[idx++] != VoltType.NULL_BIGINT);
            this.expect_buyer    = ((Long)params[idx++] != VoltType.NULL_BIGINT);
            this.expect_watched  = ((Long)params[idx++] != VoltType.NULL_BIGINT);
        }
        @Override
        public void process(VoltTable[] results) {
            int idx = 0;
           
            // USER
            if (expect_user) {
                VoltTable vt = results[idx++];
                assert(vt != null);
                assert(vt.getRowCount() > 0);
            }
            // USER_FEEDBACK
            if (expect_feedback) {
                VoltTable vt = results[idx++];
                assert(vt != null);
            }
            // ITEM_COMMENT
            if (expect_comments) {
                VoltTable vt = results[idx++];
                assert(vt != null);
                while (vt.advanceRow()) {
                    long vals[] = {
                        vt.getLong("ic_id"),
                        vt.getLong("ic_i_id"),
                        vt.getLong("ic_u_id")
                    };
                    pending_commentResponse.add(vals);
                } // WHILE
            }
           
            // ITEM Result Tables
            for (int i = idx; i < results.length; i++) {
                VoltTable vt = results[i];
                assert(vt != null);
                while (vt.advanceRow()) {
                    ItemId itemId = this.processItemRecord(vt);
                    assert(itemId != null);
                } // WHILE
            } // FOR
        }
    } // END CLASS
   
    /**********************************************************************************************
     * NEW_BID Callback
     **********************************************************************************************/
    protected class NewBidCallback extends BaseCallback {
        public NewBidCallback(Object params[]) {
            super(Transaction.NEW_BID, params);
        }
        @Override
        public void process(VoltTable[] results) {
            assert(results.length == 1);
            while (results[0].advanceRow()) {
                ItemId itemId = this.processItemRecord(results[0]);
                assert(itemId != null);
            } // WHILE
            if (debug.val) LOG.debug(super.toString());
        }
    } // END CLASS

    /**********************************************************************************************
     * NEW_ITEM Callback
     **********************************************************************************************/
    protected class NewItemCallback extends BaseCallback {
        public NewItemCallback(Object params[]) {
            super(Transaction.NEW_ITEM, params);
        }
        @Override
        public void process(VoltTable[] results) {
            assert(results.length == 1);
            while (results[0].advanceRow()) {
                ItemId itemId = this.processItemRecord(results[0]);
                assert(itemId != null);
            } // WHILE
            if (debug.val) LOG.debug(super.toString());
        }
    } // END CLASS
   
    /**********************************************************************************************
     * NEW_PURCHASE Callback
     **********************************************************************************************/
    protected class NewPurchaseCallback extends BaseCallback {
        public NewPurchaseCallback(Object params[]) {
            super(Transaction.NEW_PURCHASE, params);
        }
        @Override
        public void process(VoltTable[] results) {
            assert(results.length == 1);
            while (results[0].advanceRow()) {
                ItemId itemId = this.processItemRecord(results[0]);
                assert(itemId != null);
            } // WHILE
            if (debug.val) LOG.debug(super.toString());
        }
    } // END CLASS
 
   
    public ItemId getNextItemId(UserId seller_id) {
        Integer cnt = this.seller_item_cnt.get(seller_id);
        if (cnt == null || cnt == 0) {
            cnt = (int)seller_id.getItemCount();
        }
        this.seller_item_cnt.put(seller_id, ++cnt);
        return (new ItemId(seller_id, cnt));
    }
   
    public TimestampType[] getTimestampParameterArray() {
        return new TimestampType[] { profile.getBenchmarkStartTime(),
                                     profile.getClientStartTime() };
    }
}
TOP

Related Classes of edu.brown.benchmark.auctionmark.AuctionMarkClient$GetUserInfoCallback

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.