示例#1
0
/*
 * The generic solution to the multiplex operators is to translate
 * them to a MAL loop.
 * The call optimizer.multiplex(MOD,FCN,A1,...An) introduces the following code
 * structure:
 *
 * @verbatim
 *  A1rev:=bat.reverse(A1);
 * 	resB:= bat.new(A1);
 * barrier (h,t):= iterator.new(A1);
 * 	$1:= algebra.fetch(A1,h);
 * 	$2:= A2;	# in case of constant?
 * 	...
 * 	cr:= MOD.FCN($1,...,$n);
 *  y:=algebra.fetch(A1rev,h);
 * 	bat.insert(resB,y,cr);
 * 	redo (h,t):= iterator.next(A1);
 * end h;
 * @end verbatim
 *
 * The algorithm consists of two phases: phase one deals with
 * collecting the relevant information, phase two is the actual
 * code construction.
 */
static str
OPTexpandMultiplex(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	int i = 2, resB, iter = 0, cr;
	int hvar, tvar;
	int x, y;
	str mod, fcn;
	int *alias;
	InstrPtr q;
	int ht, tt;

	(void) cntxt;
	(void) stk;

	ht = getHeadType(getArgType(mb, pci, 0));
	if (ht != TYPE_oid)
		throw(MAL, "optimizer.multiplex", "Target head type is missing");
	tt = getTailType(getArgType(mb, pci, 0));
	if (tt== TYPE_any)
		throw(MAL, "optimizer.multiplex", "Target tail type is missing");
	if (isAnyExpression(getArgType(mb, pci, 0)))
		throw(MAL, "optimizer.multiplex", "Target type is missing");

	mod = VALget(&getVar(mb, getArg(pci, 1))->value);
	mod = putName(mod,strlen(mod));
	fcn = VALget(&getVar(mb, getArg(pci, 2))->value);
	fcn = putName(fcn,strlen(fcn));

	/* search the iterator bat */
	for (i = 3; i < pci->argc; i++)
		if (isaBatType(getArgType(mb, pci, i))) {
			iter = getArg(pci, i);
			if (getHeadType(getVarType(mb,iter)) != TYPE_oid)
				throw(MAL, "optimizer.multiplex", "Iterator BAT is not OID-headed");
			break;
		}
	if( i == pci->argc)
		throw(MAL, "optimizer.multiplex", "Iterator BAT type is missing");

	OPTDEBUGmultiplex {
		mnstr_printf(cntxt->fdout,"#calling the optimize multiplex script routine\n");
		printFunction(cntxt->fdout,mb, 0, LIST_MAL_ALL );
		mnstr_printf(cntxt->fdout,"#multiplex against operator %d %s\n",iter, getTypeName(getVarType(mb,iter)));
		printInstruction(cntxt->fdout,mb, 0, pci,LIST_MAL_ALL);
	}
	/*
	 * Beware, the operator constant (arg=1) is passed along as well,
	 * because in the end we issue a recursive function call that should
	 * find the actual arguments at the proper place of the callee.
	 */

	alias= (int*) GDKmalloc(sizeof(int) * pci->maxarg);
	if (alias == NULL)
		return NULL;

	/* x := bat.reverse(A1); */
	x = newTmpVariable(mb, newBatType(getTailType(getVarType(mb,iter)),
									  getHeadType(getVarType(mb,iter))));
	q = newFcnCall(mb, batRef, reverseRef);
	getArg(q, 0) = x;
	q = pushArgument(mb, q, iter);

	/* resB := new(refBat) */
	q = newFcnCall(mb, batRef, newRef);
	resB = getArg(q, 0);

	setVarType(mb, getArg(q, 0), newBatType(ht, tt));
	q = pushType(mb, q, ht);
	q = pushType(mb, q, tt);
	/* barrier (h,r) := iterator.new(refBat); */
	q = newFcnCall(mb, iteratorRef, newRef);
	q->barrier = BARRIERsymbol;
	hvar = newTmpVariable(mb, TYPE_any);
	getArg(q,0) = hvar;
	tvar = newTmpVariable(mb, TYPE_any);
	q= pushReturn(mb, q, tvar);
	(void) pushArgument(mb,q,iter);

	/* $1:= algebra.fetch(Ai,h) or constant */
	alias[i] = tvar;

	for (i++; i < pci->argc; i++)
		if (isaBatType(getArgType(mb, pci, i))) {
			q = newFcnCall(mb, algebraRef, "fetch");
			alias[i] = newTmpVariable(mb, getTailType(getArgType(mb, pci, i)));
			getArg(q, 0) = alias[i];
			q= pushArgument(mb, q, getArg(pci, i));
			(void) pushArgument(mb, q, hvar);
		}

	/* cr:= mod.CMD($1,...,$n); */
	q = newFcnCall(mb, mod, fcn);
	cr = getArg(q, 0) = newTmpVariable(mb, TYPE_any);

	for (i = 3; i < pci->argc; i++)
		if (isaBatType(getArgType(mb, pci, i))) {
			q= pushArgument(mb, q, alias[i]);
		} else {
			q = pushArgument(mb, q, getArg(pci, i));
		}

	/* y := algebra.fetch(x,h); */
	y = newTmpVariable(mb, getHeadType(getVarType(mb,iter)));
	q = newFcnCall(mb, algebraRef, "fetch");
	getArg(q, 0) = y;
	q = pushArgument(mb, q, x);
	q = pushArgument(mb, q, hvar);

	/* insert(resB,h,cr);
	   not append(resB, cr); the head type (oid) may dynamically change */

	q = newFcnCall(mb, batRef, insertRef);
	q= pushArgument(mb, q, resB);
	q= pushArgument(mb, q, y);
	(void) pushArgument(mb, q, cr);

/* redo (h,r):= iterator.next(refBat); */
	q = newFcnCall(mb, iteratorRef, nextRef);
	q->barrier = REDOsymbol;
	getArg(q,0) = hvar;
	q= pushReturn(mb, q, tvar);
	(void) pushArgument(mb,q,iter);

	q = newAssignment(mb);
	q->barrier = EXITsymbol;
	getArg(q,0) = hvar;
	(void) pushReturn(mb, q, tvar);

	q = newAssignment(mb);
	getArg(q, 0) = getArg(pci, 0);
	(void) pushArgument(mb, q, resB);
	GDKfree(alias);
	return MAL_SUCCEED;
}
示例#2
0
int 
OPTquerylogImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	int i, limit, slimit;
	InstrPtr p = 0, *old= mb->stmt, q,r;
	int argc, io, user,nice,sys,idle,iowait,load, arg, start,finish, name;
	int xtime=0, rtime = 0, tuples=0;
	InstrPtr defineQuery = NULL;


	// query log needed?
	if ( !QLOGisset() )
		return 0;
	(void) pci;
	(void) stk;		/* to fool compilers */
	(void) cntxt;
	/* gather information */
	for (i = 1; i < mb->stop; i++) {
		p = getInstrPtr(mb,i);
		if ( getModuleId(p) && idcmp(getModuleId(p), "querylog") == 0 && idcmp(getFunctionId(p),"define")==0){
			defineQuery= p;
			getVarConstant(mb,getArg(p,3)).val.lval = GDKusec()-getVarConstant(mb,getArg(p,3)).val.lval ;
		}
	}
	if ( defineQuery == NULL)
		/* nothing to do */
		return 0;

	limit= mb->stop;
	slimit= mb->ssize;
	if ( newMalBlkStmt(mb, mb->ssize) < 0)
		return 0; 

	pushInstruction(mb, old[0]);
	/* run the querylog.define operation */
	defineQuery = copyInstruction(defineQuery);
	setFunctionId(defineQuery, insertRef);
	getArg(defineQuery,0) = newTmpVariable(mb,TYPE_any);
	defineQuery->token = ASSIGNsymbol;
	setModuleId(defineQuery,querylogRef);

	/* collect the initial statistics */
	q = newStmt(mb, "clients", "getUsername");
	name= getArg(q,0)= newVariable(mb,GDKstrdup("name"),TYPE_str);
	defineQuery = pushArgument(mb,defineQuery,name);
	q = newStmt(mb, "mtime", "current_timestamp");
	start= getArg(q,0)= newVariable(mb,GDKstrdup("start"),TYPE_timestamp);
	defineQuery = pushArgument(mb,defineQuery,start);
	pushInstruction(mb, defineQuery);

	q = newStmt1(mb, sqlRef, "argRecord");
	for ( argc=1; argc < old[0]->argc; argc++)
		q = pushArgument(mb, q, getArg(old[0],argc));

	arg= getArg(q,0)= newVariable(mb,GDKstrdup("args"),TYPE_str);


	q = newStmt(mb, "alarm", "usec");
	xtime = getArg(q,0)= newVariable(mb,GDKstrdup("xtime"),TYPE_lng);
	user = newVariable(mb,GDKstrdup("user"),TYPE_lng);
	nice = newVariable(mb,GDKstrdup("nice"),TYPE_lng);
	sys = newVariable(mb,GDKstrdup("sys"),TYPE_lng);
	idle = newVariable(mb,GDKstrdup("idle"),TYPE_lng);
	iowait = newVariable(mb,GDKstrdup("iowait"),TYPE_lng);
	q = newStmt(mb, "profiler", "cpustats");
	q->retc= q->argc =0;
	q = pushReturn(mb,q,user);
	q = pushReturn(mb,q,nice);
	q = pushReturn(mb,q,sys);
	q = pushReturn(mb,q,idle);
	q = pushReturn(mb,q,iowait);
	q = newAssignment(mb);
	tuples= getArg(q,0) = newVariable(mb,GDKstrdup("tuples"),TYPE_wrd);
	(void) pushWrd(mb,q,1);

	for (i = 1; i < limit; i++) {
		p = old[i];
		
		if (getModuleId(p)==sqlRef && 
			(idcmp(getFunctionId(p),"exportValue")==0 ||
			 idcmp(getFunctionId(p),"exportResult")==0  ) ) {

			q = newStmt(mb, "alarm", "usec");
			r = newStmt1(mb, calcRef, "-");
			r = pushArgument(mb, r, getArg(q,0));
			r = pushArgument(mb, r, xtime);
			getArg(r,0)=xtime;

			q = newStmt(mb, "alarm", "usec");
			rtime= getArg(q,0)= newVariable(mb,GDKstrdup("rtime"),TYPE_lng);
			pushInstruction(mb,p);
			continue;
		}
		if ( getModuleId(p) == sqlRef && idcmp(getFunctionId(p),"resultSet")==0  && isaBatType(getVarType(mb,getArg(p,3)))){
			q = newStmt(mb, "aggr", "count");
			getArg(q,0) = tuples;
			(void) pushArgument(mb,q, getArg(p,3));
			pushInstruction(mb,p);
			continue;
		}	
		if ( p->token== ENDsymbol || p->barrier == RETURNsymbol || p->barrier == YIELDsymbol){
			if ( rtime == 0){
				q = newStmt(mb, "alarm", "usec");
				r = newStmt1(mb, calcRef, "-");
				r = pushArgument(mb, r, getArg(q,0));
				r = pushArgument(mb, r, xtime);
				getArg(r,0)=xtime;
				q = newStmt(mb, "alarm", "usec");
				rtime= getArg(q,0)= newVariable(mb,GDKstrdup("rtime"),TYPE_lng);
			}
			q = newStmt(mb, "alarm", "usec");
			r = newStmt1(mb, calcRef, "-");
			r = pushArgument(mb, r, getArg(q,0));
			r = pushArgument(mb, r, rtime);
			getArg(r,0)=rtime;
			/*
			 * Post execution statistics gathering
			 */
			q = newStmt(mb, "mtime", "current_timestamp");
			finish= getArg(q,0)= newVariable(mb,GDKstrdup("finish"),TYPE_any);

			q = newStmt(mb, "profiler", "cpuload");
			load = newVariable(mb,GDKstrdup("load"),TYPE_int);
			getArg(q,0)= load;
			io = newVariable(mb,GDKstrdup("io"),TYPE_int);
			q= pushReturn(mb,q,io);
			q = pushArgument(mb,q,user);
			q = pushArgument(mb,q,nice);
			q = pushArgument(mb,q,sys);
			q = pushArgument(mb,q,idle);
			q = pushArgument(mb,q,iowait);

			q = newStmt(mb, querylogRef, "call");
			q = pushArgument(mb, q, start);
			q = pushArgument(mb, q, finish); 
			q = pushArgument(mb, q, arg);
			q = pushArgument(mb, q, tuples); 
			q = pushArgument(mb, q, xtime); 
			q = pushArgument(mb, q, rtime); 
			q = pushArgument(mb, q, load); 
			q = pushArgument(mb, q, io); 
			pushInstruction(mb,p);
			continue;
		}

		pushInstruction(mb,p);
		if (p->barrier == YIELDsymbol){
			/* the factory yield may return */
			q = newStmt(mb, "mtime", "current_timestamp");
			start= getArg(q,0)= newVariable(mb,GDKstrdup("start"),TYPE_any);
			q = newStmt1(mb, sqlRef, "argRecord");
			for ( argc=1; argc < old[0]->argc; argc++)
				q = pushArgument(mb, q, getArg(old[0],argc));
			arg= getArg(q,0)= newVariable(mb,GDKstrdup("args"),TYPE_str);
			q = newAssignment(mb);
			q = pushLng(mb,q,0);
			q = newAssignment(mb);
			q = pushWrd(mb,q,0);
			tuples= getArg(q,0)= newVariable(mb,GDKstrdup("tuples"),TYPE_wrd);
			newFcnCall(mb,"profiler","setMemoryFlag");
			q->argc--;
			pushWrd(mb,q,1);
			q = newStmt(mb, "alarm", "usec");
			xtime = getArg(q,0)= newVariable(mb,GDKstrdup("xtime"),TYPE_lng);
		}
	}

	for( ; i<slimit; i++)
		if(old[i])
			freeInstruction(old[i]);
	GDKfree(old);
	return 1;
}
示例#3
0
int
OPTrecyclerImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
{
	int i, j, cnt, tp, c, actions = 0, marks = 0, delta = 0;
	Lifespan span;
	InstrPtr *old, q;
	int limit, updstmt = 0;
	char *recycled;
	short app_sc = -1, in = 0;
	ValRecord cst;

	(void) cntxt;
	(void) stk;

	limit = mb->stop;
	old = mb->stmt;

	for (i = 1; i < limit; i++) {
		p = old[i];
		if (getModuleId(p) == sqlRef &&
				(getFunctionId(p) == affectedRowsRef ||
				 getFunctionId(p) == exportOperationRef ||
				 getFunctionId(p) == appendRef ||
				 getFunctionId(p) == updateRef ||
				 getFunctionId(p) == deleteRef))
			updstmt = 1;
	}

	span = setLifespan(mb);
	if (span == NULL)
		return 0;

	/* watch out, newly created instructions may introduce new variables */
	recycled = GDKzalloc(sizeof(char) * mb->vtop * 2);
	if (recycled == NULL)
		return 0;
	if (newMalBlkStmt(mb, mb->ssize) < 0) {
		GDKfree(recycled);
		return 0;
	}
	pushInstruction(mb, old[0]);
	mb->recid = recycleSeq++;

	/* create a handle for recycler */
	(void) newFcnCall(mb, "recycle", "prelude");
	in = 1;
	for (i = 1; i < limit; i++) {
		p = old[i];
		if (hasSideEffects(p, TRUE) || isUpdateInstruction(p) || isUnsafeFunction(p)) {
			if (getModuleId(p) == recycleRef) { /*don't inline recycle instr. */
				freeInstruction(p);
				continue;
			}
			pushInstruction(mb, p);
			/*  update instructions are not recycled but monitored*/
			if (isUpdateInstruction(p)) {
				if (getModuleId(p) == batRef &&
					(getArgType(mb, p, 1) == TYPE_bat
					 || isaBatType(getArgType(mb, p, 1)))) {
					recycled[getArg(p, 1)] = 0;
					q = newFcnCall(mb, "recycle", "reset");
					pushArgument(mb, q, getArg(p, 1));
					actions++;
				}
				if (getModuleId(p) == sqlRef) {
					if (getFunctionId(p) == appendRef) {
						if (app_sc >= 0)
							continue;
						else
							app_sc = getArg(p, 2);
					}
					VALset(&cst, TYPE_int, &delta);
					c = defConstant(mb, TYPE_int, &cst);
					q = newFcnCall(mb, "recycle", "reset");
					pushArgument(mb, q, c);
					pushArgument(mb, q, getArg(p, 2));
					pushArgument(mb, q, getArg(p, 3));
					if (getFunctionId(p) == updateRef)
						pushArgument(mb, q, getArg(p, 4));
					actions++;
				}
			}
			/* take care of SQL catalog update instructions */
			if (getModuleId(p) == sqlRef && getFunctionId(p) == catalogRef) {
				tp = *(int *) getVarValue(mb, getArg(p, 1));
				if (tp == 22 || tp == 25) {
					delta = 2;
					VALset(&cst, TYPE_int, &delta);
					c = defConstant(mb, TYPE_int, &cst);
					q = newFcnCall(mb, "recycle", "reset");
					pushArgument(mb, q, c);
					pushArgument(mb, q, getArg(p, 2));
					if (tp == 25)
						pushArgument(mb, q, getArg(p, 3));
					actions++;
				}
			}
			continue;
		}
		if (p->token == ENDsymbol || p->barrier == RETURNsymbol) {
			if (in) {
				/*
				if (updstmt && app_sc >= 0) {
					q = newFcnCall(mb, "recycle", "reset");
					pushArgument(mb, q, app_sc);
					pushArgument(mb, q, app_tbl);
				}
				 */
				(void) newFcnCall(mb, "recycle", "epilogue");
				in = 0;
			}
			pushInstruction(mb, p);
			continue;
		}

		if (p->barrier && p->token != CMDcall) {
			/* never save a barrier unless it is a command and side-effect free */
			pushInstruction(mb, p);
			continue;
		}

		/* don't change instructions in update statements */
		if (updstmt) {
			pushInstruction(mb, p);
			continue;
		}

		/* skip simple assignments */
		if (p->token == ASSIGNsymbol) {
			pushInstruction(mb, p);
			continue;
		}

		if (getModuleId(p) == octopusRef &&
			(getFunctionId(p) == bindRef || getFunctionId(p) == bindidxRef)) {
			recycled[getArg(p, 0)] = 1;
			p->recycle = recycleMaxInterest;
			marks++;
		}
		/* During base table recycling skip marking instructions other than octopus.bind */
		if (baseTableMode) {
			pushInstruction(mb, p);
			continue;
		}

		/* general rule: all arguments are constants or recycled,
		   ignore C pointer arguments from mvc */
		cnt = 0;
		for (j = p->retc; j < p->argc; j++)
			if (recycled[getArg(p, j)] || isVarConstant(mb, getArg(p, j))
					|| ignoreVar(mb, getArg(p, j)))
				cnt++;
		if (cnt == p->argc - p->retc) {
			OPTDEBUGrecycle {
				mnstr_printf(cntxt->fdout, "#recycle instruction\n");
				printInstruction(cntxt->fdout, mb, 0, p, LIST_MAL_ALL);
			}
			marks++;
			p->recycle = recycleMaxInterest; /* this instruction is to be monitored */
			for (j = 0; j < p->retc; j++)
				if (getLastUpdate(span, getArg(p, j)) == i)
					recycled[getArg(p, j)] = 1;
		}
		/*
		 * The expected gain is largest if we can re-use selections
		 * on the base tables in SQL. These, however, are marked as
		 * uselect() calls, which only produce the oid head.
		 * For cheap types we preselect using select() and re-map uselect() back
		 * over this temporary.
		 * For the time being for all possible selects encountered
		 * are marked for re-use.
		 */
		/* take care of semantic driven recyling */
		/* for selections check the bat argument only
		   the range is often template parameter*/
		if ((getFunctionId(p) == selectRef ||
					getFunctionId(p) == antiuselectRef ||
					getFunctionId(p) == likeselectRef ||
					getFunctionId(p) == likeRef ||
					getFunctionId(p) == thetaselectRef) &&
				recycled[getArg(p, 1)])
		{
			p->recycle = recycleMaxInterest;
			marks++;
			if (getLastUpdate(span, getArg(p, 0)) == i)
				recycled[getArg(p, 0)] = 1;
		}
		if ((getFunctionId(p) == uselectRef || getFunctionId(p) == thetauselectRef)
				&& recycled[getArg(p, 1)])
		{
			if (!ATOMvarsized(getGDKType(getArgType(mb, p, 2)))) {
				q = copyInstruction(p);
				getArg(q, 0) = newTmpVariable(mb, TYPE_any);
				if (getFunctionId(p) == uselectRef)
					setFunctionId(q, selectRef);
				else
					setFunctionId(q, thetaselectRef);
				q->recycle = recycleMaxInterest;
				marks++;
				recycled[getArg(q, 0)] = 1;
				pushInstruction(mb, q);
				getArg(p, 1) = getArg(q, 0);
				setFunctionId(p, projectRef);
				p->argc = 2;
			}
			p->recycle = recycleMaxInterest;
			marks++;
			if (getLastUpdate(span, getArg(p, 0)) == i)
				recycled[getArg(p, 0)] = 1;
		}

		if (getModuleId(p) == pcreRef) {
			if ((getFunctionId(p) == selectRef && recycled[getArg(p, 2)]) ||
				(getFunctionId(p) == uselectRef && recycled[getArg(p, 2)])) {
				p->recycle = recycleMaxInterest;
				marks++;
				if (getLastUpdate(span, getArg(p, 0)) == i)
					recycled[getArg(p, 0)] = 1;
			} else if (getFunctionId(p) == likeuselectRef && recycled[getArg(p, 1)]) {
				q = copyInstruction(p);
				getArg(q, 0) = newTmpVariable(mb, TYPE_any);
				setFunctionId(q, likeselectRef);
				q->recycle = recycleMaxInterest;
				recycled[getArg(q, 0)] = 1;
				pushInstruction(mb, q);
				getArg(p, 1) = getArg(q, 0);
				setFunctionId(p, projectRef);
				setModuleId(p, algebraRef);
				p->argc = 2;
				p->recycle = recycleMaxInterest;
				marks += 2;
				if (getLastUpdate(span, getArg(p, 0)) == i)
					recycled[getArg(p, 0)] = 1;
			}
		}

		/*
		 * The sql.bind instructions should be handled carefully
		 * The delete and update BATs should not be recycled,
		 * because they may lead to view dependencies that later interferes
		 * with the transaction commits.
		 */
		/* enable recycling of delta-bats
		if (getModuleId(p) == sqlRef &&
				(((getFunctionId(p) == bindRef || getFunctionId(p) == putName("bind_idxbat", 11)) &&
				  getVarConstant(mb, getArg(p, 5)).val.ival != 0) ||
				 getFunctionId(p) == binddbatRef)) {
			recycled[getArg(p, 0)] = 0;
			p->recycle = REC_NO_INTEREST;
		}
		*/

/*
 * The sql.bind instructions should be handled carefully
 * The delete and update BATs should not be recycled,
 * because they may lead to view dependencies that later interferes
 * with the transaction commits.
 */
/* enable recycling of delta-bats
		if (getModuleId(p)== sqlRef && 
			(((getFunctionId(p)==bindRef || getFunctionId(p) == putName("bind_idxbat",11)) && 
				getVarConstant(mb, getArg(p,5)).val.ival != 0) ||
				getFunctionId(p)== binddbatRef) ) {
				recycled[getArg(p,0)]=0;
				p->recycle = REC_NO_INTEREST; 
			}
*/

		pushInstruction(mb, p);
	}
示例#4
0
/*
 * The generic solution to the multiplex operators is to translate
 * them to a MAL loop.
 * The call optimizer.multiplex(MOD,FCN,A1,...An) introduces the following code
 * structure:
 *
 * 	resB:= bat.new(A1);
 * barrier (h,t1):= iterator.new(A1);
 * 	t2:= algebra.fetch(A2,h)
 * 	...
 * 	cr:= MOD.FCN(t1,...,tn);
 * 	bat.append(resB,cr);
 * 	redo (h,t):= iterator.next(A1);
 * end h;
 *
 * The algorithm consists of two phases: phase one deals with
 * collecting the relevant information, phase two is the actual
 * code construction.
 */
static str
OPTexpandMultiplex(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	int i = 2, iter = 0;
	int hvar, tvar;
	str mod, fcn;
	int *alias, *resB;
	InstrPtr q;
	int tt;
	int bat = (getModuleId(pci) == batmalRef) ;

	//if ( optimizerIsApplied(mb,"multiplex"))
		//return 0;
	(void) cntxt;
	(void) stk;
	for (i = 0; i < pci->retc; i++) {
		tt = getBatType(getArgType(mb, pci, i));
		if (tt== TYPE_any)
			throw(MAL, "optimizer.multiplex", SQLSTATE(HY002) "Target tail type is missing");
		if (isAnyExpression(getArgType(mb, pci, i)))
			throw(MAL, "optimizer.multiplex", SQLSTATE(HY002) "Target type is missing");
	}

	mod = VALget(&getVar(mb, getArg(pci, pci->retc))->value);
	mod = putName(mod);
	fcn = VALget(&getVar(mb, getArg(pci, pci->retc+1))->value);
	fcn = putName(fcn);
	if(mod == NULL || fcn == NULL)
		throw(MAL, "optimizer.multiplex", SQLSTATE(HY001) MAL_MALLOC_FAIL);
#ifndef NDEBUG
	fprintf(stderr,"#WARNING To speedup %s.%s a bulk operator implementation is needed\n#", mod,fcn);
	fprintInstruction(stderr, mb, stk, pci, LIST_MAL_DEBUG);
#endif

	/* search the iterator bat */
	for (i = pci->retc+2; i < pci->argc; i++)
		if (isaBatType(getArgType(mb, pci, i))) {
			iter = getArg(pci, i);
			break;
		}
	if( i == pci->argc)
		throw(MAL, "optimizer.multiplex", SQLSTATE(HY002) "Iterator BAT type is missing");

#ifdef DEBUG_OPT_MULTIPLEX
	{	char *tpenme;
		fprintf(stderr,"#calling the optimize multiplex script routine\n");
		fprintFunction(stderr,mb, 0, LIST_MAL_ALL );
		tpenme = getTypeName(getVarType(mb,iter));
		fprintf(stderr,"#multiplex against operator %d %s\n",iter, tpenme);
		GDKfree(tpenme);
		fprintInstruction(stderr,mb, 0, pci,LIST_MAL_ALL);
	}
#endif
	/*
	 * Beware, the operator constant (arg=1) is passed along as well,
	 * because in the end we issue a recursive function call that should
	 * find the actual arguments at the proper place of the callee.
	 */

	alias= (int*) GDKmalloc(sizeof(int) * pci->maxarg);
	resB = (int*) GDKmalloc(sizeof(int) * pci->retc);
	if (alias == NULL || resB == NULL)  {
		GDKfree(alias);
		GDKfree(resB);
		return NULL;
	}

	/* resB := new(refBat) */
	for (i = 0; i < pci->retc; i++) {
		q = newFcnCall(mb, batRef, newRef);
		resB[i] = getArg(q, 0);

		tt = getBatType(getArgType(mb, pci, i));

		setVarType(mb, getArg(q, 0), newBatType(tt));
		q = pushType(mb, q, tt);
	}

	/* barrier (h,r) := iterator.new(refBat); */
	q = newFcnCall(mb, iteratorRef, newRef);
	q->barrier = BARRIERsymbol;
	hvar = newTmpVariable(mb, TYPE_any);
	getArg(q,0) = hvar;
	tvar = newTmpVariable(mb, TYPE_any);
	q= pushReturn(mb, q, tvar);
	(void) pushArgument(mb,q,iter);

	/* $1:= algebra.fetch(Ai,h) or constant */
	for (i = pci->retc+2; i < pci->argc; i++) {
		if (getArg(pci, i) != iter && isaBatType(getArgType(mb, pci, i))) {
			q = newFcnCall(mb, algebraRef, "fetch");
			alias[i] = newTmpVariable(mb, getBatType(getArgType(mb, pci, i)));
			getArg(q, 0) = alias[i];
			q= pushArgument(mb, q, getArg(pci, i));
			(void) pushArgument(mb, q, hvar);
		}
	}

	/* cr:= mod.CMD($1,...,$n); */
	q = newFcnCall(mb, mod, fcn);
	for (i = 0; i < pci->retc; i++) {
		int nvar = 0;
		if (bat) {
			tt = getBatType(getArgType(mb, pci, i));
			nvar = newTmpVariable(mb, newBatType(tt));
		} else {
			nvar = newTmpVariable(mb, TYPE_any);
		}
		if (i)
			q = pushReturn(mb, q, nvar);
		else
			getArg(q, 0) = nvar;
	}

	for (i = pci->retc+2; i < pci->argc; i++) {
		if (getArg(pci, i) == iter) {
			q = pushArgument(mb, q, tvar);
		} else if (isaBatType(getArgType(mb, pci, i))) {
			q = pushArgument(mb, q, alias[i]);
		} else {
			q = pushArgument(mb, q, getArg(pci, i));
		}
	}

	for (i = 0; i < pci->retc; i++) {
		InstrPtr a = newFcnCall(mb, batRef, appendRef);
		a = pushArgument(mb, a, resB[i]);
		(void) pushArgument(mb, a, getArg(q,i));
	}

/* redo (h,r):= iterator.next(refBat); */
	q = newFcnCall(mb, iteratorRef, nextRef);
	q->barrier = REDOsymbol;
	getArg(q,0) = hvar;
	q= pushReturn(mb, q, tvar);
	(void) pushArgument(mb,q,iter);

	q = newAssignment(mb);
	q->barrier = EXITsymbol;
	getArg(q,0) = hvar;
	(void) pushReturn(mb, q, tvar);

	for (i = 0; i < pci->retc; i++) {
		q = newAssignment(mb);
		getArg(q, 0) = getArg(pci, i);
		(void) pushArgument(mb, q, resB[i]);
	}
	GDKfree(alias);
	GDKfree(resB);
	return MAL_SUCCEED;
}
示例#5
0
int
OPTrecyclerImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	int i, j, cnt, cand, actions = 1, marks = 0;
	InstrPtr *old, q,p;
	int limit;
	char *recycled;

	(void) cntxt;
	(void) stk;
	(void) pci;

	limit = mb->stop;
	old = mb->stmt;

	/* watch out, newly created instructions may introduce new variables */
	recycled = GDKzalloc(sizeof(char) * mb->vtop * 2);
	if (recycled == NULL)
		return 0;
	if (newMalBlkStmt(mb, mb->ssize) < 0) {
		GDKfree(recycled);
		return 0;
	}
	pushInstruction(mb, old[0]);
	for (i = 1; i < limit; i++) {
		p = old[i];
		if (p->token == ENDsymbol )
			break;
		/* the first non-dataflow barrier breaks the recycler code*/
		if (blockStart(p) && !(getFunctionId(p) && getFunctionId(p) == dataflowRef) )
			break;

		if ( isUpdateInstruction(p) || hasSideEffects(p,TRUE)){
			/*  update instructions are not recycled but monitored*/
			pushInstruction(mb, p);
			if (isUpdateInstruction(p)) {
				if (getModuleId(p) == batRef && isaBatType(getArgType(mb, p, 1))) {
					q = newFcnCall(mb, "recycle", "reset");
					pushArgument(mb, q, getArg(p, 1));
					actions++;
				}
				if (getModuleId(p) == sqlRef) {
					q= copyInstruction(p);
					getModuleId(q) = recycleRef;
					actions++;
				}
			}
			continue;
		}
		// Not all instruction may be recycled. In particular, we should avoid
		// MAL function with implicit/recursive side effects. 
		// This can not always be detected easily. Likewise, we ignore cheap operations
		// Therefore, we use a safe subset to start with
		if ( ! (getModuleId(p) == sqlRef || getModuleId(p)== batRef || 
				getModuleId(p) == algebraRef || getModuleId(p)==batcalcRef ||
				getModuleId(p)== aggrRef || getModuleId(p)== groupRef ||
				getModuleId(p)== batstrRef || getModuleId(p)== batmmathRef ||
				getModuleId(p)== arrayRef || getModuleId(p)== batmtimeRef ||
				getModuleId(p)== batcalcRef || getModuleId(p)== pcreRef ||
				getModuleId(p)== mtimeRef || getModuleId(p) == calcRef  ||
				getModuleId(p)== dateRef || getModuleId(p) == timestampRef  ||
				getModuleId(p)== matRef )
			){
			pushInstruction(mb,p);
			continue;
		}

		/* general rule: all arguments should be constants or recycled*/
		cnt = 0;
		for (j = p->retc; j < p->argc; j++)
			if (recycled[getArg(p, j)] || isVarConstant(mb, getArg(p, j)) || isFunctionArgument(mb,getArg(p,j)) )
				cnt++;
		cand = 0;
		for (j =0; j< p->retc; j++)
			if (recycled[getArg(p, j)] ==0)
				cand++;
		if (cnt == p->argc - p->retc && cand == p->retc) {
			marks++;
			p->recycle = RECYCLING; /* this instruction is to be monitored */
			for (j = 0; j < p->retc; j++)
				recycled[getArg(p, j)] = 1;
		}
		pushInstruction(mb, p);
	}
	for (; i < limit; i++) 
		pushInstruction(mb, old[i]);
	GDKfree(old);
	GDKfree(recycled);
	mb->recycle = marks > 0;
	OPTDEBUGrecycle {
		mnstr_printf(cntxt->fdout, "#recycle optimizer: ");
		printFunction(cntxt->fdout,mb, 0, LIST_MAL_ALL);
	}
	return actions + marks;
}