/* This file is part of VoltDB.
 * Copyright (C) 2008-2013 VoltDB 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 txnIdSelfCheck;

import java.util.Date;
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;

import org.voltcore.logging.VoltLogger;
import org.voltdb.ClientResponseImpl;
import org.voltdb.client.Client;
import org.voltdb.client.ClientResponse;
import org.voltdb.client.NoConnectionsException;
import org.voltdb.client.ProcedureCallback;

public class AdHocMayhemThread extends Thread {

    static VoltLogger log = new VoltLogger("HOST");

    Random r = new Random(0);
    long counter = 0;
    final Client client;
    final AtomicBoolean m_shouldContinue = new AtomicBoolean(true);
    final AtomicBoolean m_needsBlock = new AtomicBoolean(false);
    final Semaphore txnsOutstanding = new Semaphore(100);

    public AdHocMayhemThread(Client client) {
        this.client = client;
    }

    private String nextAdHoc() {
        // 1/5 of all adhocs are MP
        boolean replicated = (counter++ % 5) == 0;

        String sql = "update";
        sql += replicated ? " adhocr " : " adhocp";
        sql += " set";
        sql += " ts = " + new Date().getTime() + ",";
        sql += " inc = inc + 1,";
        sql += " jmp = jmp + " + r.nextInt(10);
        if (!replicated) {
            sql += " where id = " + r.nextInt(10);
        }
        sql += ";";

        return sql;
    }

    void shutdown() {
        m_shouldContinue.set(false);
    }

    class AdHocCallback implements ProcedureCallback {
        @Override
        public void clientCallback(ClientResponse clientResponse) throws Exception {
            txnsOutstanding.release();
            if (clientResponse.getStatus() != ClientResponse.SUCCESS) {
                log.warn("Non success in ProcCallback for AdHocMayhemThread. Will sleep.");
                log.warn(((ClientResponseImpl)clientResponse).toJSONString());
                m_needsBlock.set(true);
            }
        }
    }

    @Override
    public void run() {
        try {
            client.callProcedure("SetupAdHocTables");
        } catch (Exception e) {
            log.error("SetupAdHocTables failed in AdHocMayhemThread. Will exit.", e);
            System.exit(-1);
        }


        while (m_shouldContinue.get()) {

            // if a transaction callback has failed, sleep for 3 seconds
            // if not, connected, continue to sleep
            if (m_needsBlock.get()) {
                do {
                    try { Thread.sleep(3000); } catch (Exception e) {} // sleep for 3s
                    // bail on wakeup if we're supposed to bail
                    if (!m_shouldContinue.get()) {
                        return;
                    }
                }
                while (client.getConnectedHostList().size() == 0);
                m_needsBlock.set(false);
            }

            // get a permit to send a transaction
            try {
                txnsOutstanding.acquire();
            } catch (InterruptedException e) {
                log.error("AdHocMayhemThread interrupted while waiting for permit. Will end AdHoc work.", e);
                return;
            }

            // call a transaction
            String sql = nextAdHoc();
            try {
                client.callProcedure(new AdHocCallback(), "@AdHoc", sql);
            }
            catch (NoConnectionsException e) {
                log.error("AdHocMayhemThread got NoConnectionsException on proc call. Will sleep.");
                m_needsBlock.set(true);
            }
            catch (Exception e) {
                log.error("AdHocMayhemThread failed to run an AdHoc statement. Will exit.", e);
                System.exit(-1);
            }
        }
    }
}

@@ -2018,24 +2018,25 @@
 xtAdHoc() %7B%0A
+%0A
         // 1
@@ -2100,10 +2100,8 @@
 nter
-++
  %25 5
@@ -2108,16 +2108,691 @@
 ) == 0;%0A
+        boolean batched = (counter %25 11) == 0;%0A%0A        // batched statements can go rw, wr or ww%0A        long rwMix = counter %25 3;%0A%0A        String sql = %22%22;%0A%0A        if (batched) %7B%0A            if (rwMix == 0) %7B%0A                sql += nextWriteAdHocStmt(replicated);%0A            %7D%0A            if (rwMix == 1) %7B%0A                sql += nextReadAdHocStmt(replicated);%0A            %7D%0A        %7D%0A%0A        sql += nextWriteAdHocStmt(replicated);%0A%0A        if (batched) %7B%0A            if (rwMix == 2) %7B%0A                sql += nextReadAdHocStmt(replicated);%0A            %7D%0A        %7D%0A        counter++;%0A%0A        return sql;%0A    %7D%0A%0A    private String nextWriteAdHocStmt(boolean replicated) %7B
 %0A       
@@ -3158,24 +3158,329 @@
 sql;%0A    %7D%0A%0A
+    private String nextReadAdHocStmt(boolean replicated) %7B%0A        String sql = %22select * from%22;%0A        sql += replicated ? %22 adhocr %22 : %22 adhocp%22;%0A        if (!replicated) %7B%0A            sql += %22 where id = %22 + r.nextInt(10);%0A        %7D%0A        sql += %22 order by id limit 1;%22;%0A%0A        return sql;%0A    %7D%0A%0A
     void shu
@@ -4308,17 +4308,16 @@
      %7D%0A%0A
-%0A
         

Add batches to AdHoc workload in txnid-selfcheck2.