<commit_before>/*
 * casstcl_futures - Functions used to create, delete, and handle futures
 *
 * casstcl - Tcl interface to CassDB
 *
 * Copyright (C) 2014 FlightAware LLC
 *
 * freely redistributable under the Berkeley license
 */

#include "casstcl.h"
#include "casstcl_cassandra.h"
#include "casstcl_future.h"
#include "casstcl_error.h"
#include "casstcl_event.h"

#include <assert.h>

/*
 *----------------------------------------------------------------------
 *
 * casstcl_future_eventProc --
 *
 *    this routine is called by the Tcl event handler to process callbacks
 *    we have set up from future (result objects) we've gotten from Cassandra
 *
 * Results:
 *    The callback routine set when the async method was invoked is
 *    invoked in the Tcl interpreter with one argument, that being the
 *    future object that was also created when the async method was
 *    invoked
 *
 *    If an uncaught error occurs when evaluating the command, a Tcl
 *    background exception is invoked
 *
 *----------------------------------------------------------------------
 */
int
casstcl_future_eventProc (Tcl_Event *tevPtr, int flags) {

	// we got called with a Tcl_Event pointer but really it's a pointer to
	// our casstcl_futureEvent structure that has the Tcl_Event plus a pointer
	// to casstcl_futureClientData, which is our key to the kindgdom.
	// Go get that.

	casstcl_futureEvent *evPtr = (casstcl_futureEvent *)tevPtr;
	casstcl_futureClientData *fcd = evPtr->fcd;
	assert (fcd->cass_future_magic == CASS_FUTURE_MAGIC);
	Tcl_Interp *interp = fcd->ct->interp;

	// eval the command.  it should be the callback we were told as the
	// first argument and the future object we created, like future0, as
	// the second.

	CassError rc = cass_future_error_code(fcd->future);
	
	// Callback if we have an error OR if CASSTCL_FUTURE_CALLBACK_ON_ERROR_ONLY not set
	if ( ((fcd->flags & CASSTCL_FUTURE_CALLBACK_ON_ERROR_ONLY) != CASSTCL_FUTURE_CALLBACK_ON_ERROR_ONLY ) || 
		(casstcl_future_error_to_tcl(fcd->ct, rc, fcd->future) == TCL_ERROR ) ) { 
		// get the name of the future object this callback is related to
		// into an object so that we can pass it as an argument

		Tcl_Obj *futureObj = Tcl_NewObj();
		Tcl_GetCommandFullName(interp, fcd->cmdToken, futureObj);
	
		casstcl_invoke_callback_with_argument (interp, fcd->callbackObj, futureObj);
	
	} else {
	
		Tcl_DeleteCommandFromToken (interp, fcd->cmdToken);
	}

	// tell the dispatcher we handled it.  0 would mean we didn't deal with
	// it and don't want it removed from the queue
	return 1;
}

/*
 *----------------------------------------------------------------------
 *
 * casstcl_future_callback --
 *
 *    this routine is called by the cassandra cpp-driver as a callback
 *    when a callback was set up by us using cass_future_set_callback
 *
 *    this occurs when the request has completed or errored
 *
 *    this generates a Tcl event and queues it to the thread that issued
 *    the command to do an asynchronous cassandra command with callback
 *    in the first place.
 *
 *    when Tcl processes the event, casstcl_future_eventProc will be invoked.
 *    that guy will do a Tcl eval to invoke the callback
 *
 * Results:
 *    stuff
 *
 *----------------------------------------------------------------------
 */
void casstcl_future_callback (CassFuture* future, void* data) {
	casstcl_futureEvent *evPtr;

	casstcl_futureClientData *fcd = data;
	evPtr = (casstcl_futureEvent *) ckalloc (sizeof (casstcl_futureEvent));
	evPtr->event.proc = casstcl_future_eventProc;
	evPtr->fcd = fcd;
	int queueEnd = ((fcd->flags & CASSTCL_FUTURE_QUEUE_HEAD_FLAG) == CASSTCL_FUTURE_QUEUE_HEAD_FLAG) ? 
					TCL_QUEUE_HEAD : TCL_QUEUE_TAIL;
	Tcl_ThreadQueueEvent(fcd->ct->threadId, (Tcl_Event *)evPtr, queueEnd);
}

/*
 *----------------------------------------------------------------------
 *
 * casstcl_createFutureObjectCommand --
 *
 *    given a casstcl_sessionClientData pointer, a pointer to a
 *    CassFuture structure and a Tcl callback object (containing a
 *    function name), this routine creates a Tcl command like
 *    "future17" that can be invoked with method arguments to access,
 *    manipulate and destroy cassandra future objects.
 *
 * Results:
 *    A standard Tcl result
 *
 *----------------------------------------------------------------------
 */
int
casstcl_createFutureObjectCommand (casstcl_sessionClientData *ct, CassFuture *future, Tcl_Obj *callbackObj, int flags)
{
    // allocate one of our cass future objects for Tcl and configure it
	casstcl_futureClientData *fcd;

	CassError rc = cass_future_error_code (future);
	if (rc != CASS_OK) {
		casstcl_future_error_to_tcl (ct, rc, future);
		cass_future_free (future);
		return TCL_ERROR;
	}

    fcd = (casstcl_futureClientData *)ckalloc (sizeof (casstcl_futureClientData));
    fcd->cass_future_magic = CASS_FUTURE_MAGIC;
	fcd->ct = ct;
	fcd->future = future;
	fcd->flags = flags;
	Tcl_Interp *interp = ct->interp;

	if (callbackObj != NULL) {
		Tcl_IncrRefCount(callbackObj);
	}
	fcd->callbackObj = callbackObj;

	if (callbackObj != NULL) {
		cass_future_set_callback (future, casstcl_future_callback, fcd);
	}

	static unsigned long nextAutoCounter = 0;
	char *commandName;
	int    baseNameLength;

#define FUTURESTRING "future"
	baseNameLength = sizeof(FUTURESTRING) + snprintf (NULL, 0, "%lu", nextAutoCounter) + 1;
	commandName = ckalloc (baseNameLength);
	snprintf (commandName, baseNameLength, "%s%lu", FUTURESTRING, nextAutoCounter++);

    // create a Tcl command to interface to cass
    fcd->cmdToken = Tcl_CreateObjCommand (interp, commandName, casstcl_futureObjectObjCmd, fcd, casstcl_futureObjectDelete);
    Tcl_SetObjResult (interp, Tcl_NewStringObj (commandName, -1));
	ckfree(commandName);
    return TCL_OK;
}


/*
 *----------------------------------------------------------------------
 *
 * casstcl_futureObjectObjCmd --
 *
 *    dispatches the subcommands of a casstcl future-handling command
 *
 * Results:
 *    stuff
 *
 *----------------------------------------------------------------------<commit_msg>Be less smart and more lazy about calculating the name length, assume 1 byte per bit in the counter instead of "interesting" snprintf call.<commit_after>/*
 * casstcl_futures - Functions used to create, delete, and handle futures
 *
 * casstcl - Tcl interface to CassDB
 *
 * Copyright (C) 2014 FlightAware LLC
 *
 * freely redistributable under the Berkeley license
 */

#include "casstcl.h"
#include "casstcl_cassandra.h"
#include "casstcl_future.h"
#include "casstcl_error.h"
#include "casstcl_event.h"

#include <assert.h>

/*
 *----------------------------------------------------------------------
 *
 * casstcl_future_eventProc --
 *
 *    this routine is called by the Tcl event handler to process callbacks
 *    we have set up from future (result objects) we've gotten from Cassandra
 *
 * Results:
 *    The callback routine set when the async method was invoked is
 *    invoked in the Tcl interpreter with one argument, that being the
 *    future object that was also created when the async method was
 *    invoked
 *
 *    If an uncaught error occurs when evaluating the command, a Tcl
 *    background exception is invoked
 *
 *----------------------------------------------------------------------
 */
int
casstcl_future_eventProc (Tcl_Event *tevPtr, int flags) {

	// we got called with a Tcl_Event pointer but really it's a pointer to
	// our casstcl_futureEvent structure that has the Tcl_Event plus a pointer
	// to casstcl_futureClientData, which is our key to the kindgdom.
	// Go get that.

	casstcl_futureEvent *evPtr = (casstcl_futureEvent *)tevPtr;
	casstcl_futureClientData *fcd = evPtr->fcd;
	assert (fcd->cass_future_magic == CASS_FUTURE_MAGIC);
	Tcl_Interp *interp = fcd->ct->interp;

	// eval the command.  it should be the callback we were told as the
	// first argument and the future object we created, like future0, as
	// the second.

	CassError rc = cass_future_error_code(fcd->future);
	
	// Callback if we have an error OR if CASSTCL_FUTURE_CALLBACK_ON_ERROR_ONLY not set
	if ( ((fcd->flags & CASSTCL_FUTURE_CALLBACK_ON_ERROR_ONLY) != CASSTCL_FUTURE_CALLBACK_ON_ERROR_ONLY ) || 
		(casstcl_future_error_to_tcl(fcd->ct, rc, fcd->future) == TCL_ERROR ) ) { 
		// get the name of the future object this callback is related to
		// into an object so that we can pass it as an argument

		Tcl_Obj *futureObj = Tcl_NewObj();
		Tcl_GetCommandFullName(interp, fcd->cmdToken, futureObj);
	
		casstcl_invoke_callback_with_argument (interp, fcd->callbackObj, futureObj);
	
	} else {
	
		Tcl_DeleteCommandFromToken (interp, fcd->cmdToken);
	}

	// tell the dispatcher we handled it.  0 would mean we didn't deal with
	// it and don't want it removed from the queue
	return 1;
}

/*
 *----------------------------------------------------------------------
 *
 * casstcl_future_callback --
 *
 *    this routine is called by the cassandra cpp-driver as a callback
 *    when a callback was set up by us using cass_future_set_callback
 *
 *    this occurs when the request has completed or errored
 *
 *    this generates a Tcl event and queues it to the thread that issued
 *    the command to do an asynchronous cassandra command with callback
 *    in the first place.
 *
 *    when Tcl processes the event, casstcl_future_eventProc will be invoked.
 *    that guy will do a Tcl eval to invoke the callback
 *
 * Results:
 *    stuff
 *
 *----------------------------------------------------------------------
 */
void casstcl_future_callback (CassFuture* future, void* data) {
	casstcl_futureEvent *evPtr;

	casstcl_futureClientData *fcd = data;
	evPtr = (casstcl_futureEvent *) ckalloc (sizeof (casstcl_futureEvent));
	evPtr->event.proc = casstcl_future_eventProc;
	evPtr->fcd = fcd;
	int queueEnd = ((fcd->flags & CASSTCL_FUTURE_QUEUE_HEAD_FLAG) == CASSTCL_FUTURE_QUEUE_HEAD_FLAG) ? 
					TCL_QUEUE_HEAD : TCL_QUEUE_TAIL;
	Tcl_ThreadQueueEvent(fcd->ct->threadId, (Tcl_Event *)evPtr, queueEnd);
}

/*
 *----------------------------------------------------------------------
 *
 * casstcl_createFutureObjectCommand --
 *
 *    given a casstcl_sessionClientData pointer, a pointer to a
 *    CassFuture structure and a Tcl callback object (containing a
 *    function name), this routine creates a Tcl command like
 *    "future17" that can be invoked with method arguments to access,
 *    manipulate and destroy cassandra future objects.
 *
 * Results:
 *    A standard Tcl result
 *
 *----------------------------------------------------------------------
 */
int
casstcl_createFutureObjectCommand (casstcl_sessionClientData *ct, CassFuture *future, Tcl_Obj *callbackObj, int flags)
{
    // allocate one of our cass future objects for Tcl and configure it
	casstcl_futureClientData *fcd;

	CassError rc = cass_future_error_code (future);
	if (rc != CASS_OK) {
		casstcl_future_error_to_tcl (ct, rc, future);
		cass_future_free (future);
		return TCL_ERROR;
	}

    fcd = (casstcl_futureClientData *)ckalloc (sizeof (casstcl_futureClientData));
    fcd->cass_future_magic = CASS_FUTURE_MAGIC;
	fcd->ct = ct;
	fcd->future = future;
	fcd->flags = flags;
	Tcl_Interp *interp = ct->interp;

	if (callbackObj != NULL) {
		Tcl_IncrRefCount(callbackObj);
	}
	fcd->callbackObj = callbackObj;

	if (callbackObj != NULL) {
		cass_future_set_callback (future, casstcl_future_callback, fcd);
	}

	static unsigned long nextAutoCounter = 0;
	char *commandName;
	int    baseNameLength;

#define FUTURESTRING "future"
	baseNameLength = sizeof(FUTURESTRING) + 8 * sizeof(nextAutoCounter) + 1; // Allocate way more space than needed
	commandName = ckalloc (baseNameLength);
	snprintf (commandName, baseNameLength, "%s%lu", FUTURESTRING, nextAutoCounter++);

    // create a Tcl command to interface to cass
    fcd->cmdToken = Tcl_CreateObjCommand (interp, commandName, casstcl_futureObjectObjCmd, fcd, casstcl_futureObjectDelete);
    Tcl_SetObjResult (interp, Tcl_NewStringObj (commandName, -1));
	ckfree(commandName);
    return TCL_OK;
}


/*
 *----------------------------------------------------------------------
 *
 * casstcl_futureObjectObjCmd --
 *
 *    dispatches the subcommands of a casstcl future-handling command
 *
 * Results:
 *    stuff
 *
 *----------------------------------------------------------------------
{'fraction_non_alphanumeric': 0.16880064829821717, 'fraction_numerical': 0.0021880064829821718, 'mean_word_length': 2.6949101796407184, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3481137', 'n_tokens_mistral': 3891, 'n_tokens_neox': 3733, 'n_words': 1160}