Hello

2011/1/15 Noah Misch <n...@leadboat.com>:
> Hello Pavel,
>
> I'm reviewing this patch for CommitFest 2011-01.
>

Thank you very much,

I am sending a updated version with little bit more comments. But I am
sure, so somebody with good English have to edit my comments.
Minimally I hope, so your questions will be answered.

> The patch seems fully desirable.  It appropriately contains no documentation
> updates.  It contains no new tests, and that's probably fine, too; I can't 
> think
> of any corner cases where this would do something other than work correctly or
> break things comprehensively.
>
> Using your test case from here:
> http://archives.postgresql.org/message-id/aanlktikdcw+c-c4u4ngaobhpfszkb5uy_zuatdzfp...@mail.gmail.com
> I observed a 28x speedup, similar to Álvaro's report.  I also made my own test
> case, attached, to evaluate this from a somewhat different angle and also to
> consider the worst case.  With a 100 KiB string (good case), I see a 4.8x
> speedup.  With a 1 KiB string (worst case - never toasted), I see no
> statistically significant change.  This is to be expected.
>
> A few specific questions and comments follow, all minor.  Go ahead and mark 
> the
> patch ready for committer when you've acted on them, or declined to do so, to
> your satisfaction.  I don't think a re-review will be needed.
>
> Thanks,
> nm
>
> On Mon, Nov 22, 2010 at 01:46:51PM +0100, Pavel Stehule wrote:
>> *** ./pl_exec.c.orig  2010-11-16 10:28:42.000000000 +0100
>> --- ./pl_exec.c       2010-11-22 13:33:01.597726809 +0100
>
> The patch applies cleanly, but the format is slightly nonstandard (-p0 when
> applied from src/pl/plpgsql/src, rather than -p1 from the root).
>
>> ***************
>> *** 3944,3949 ****
>> --- 3965,3993 ----
>>
>>                               *typeid = var->datatype->typoid;
>>                               *typetypmod = var->datatype->atttypmod;
>> +
>> +                             /*
>> +                              * explicit deTOAST and decomprim for varlena 
>> types
>
> "decompress", perhaps?
>

fixed

>> +                              */
>> +                             if (var->should_be_detoasted)
>> +                             {
>> +                                     Datum dvalue;
>> +
>> +                                     Assert(!var->isnull);
>> +
>> +                                     oldcontext = 
>> MemoryContextSwitchTo(estate->fn_mcxt);
>> +                                     dvalue = 
>> PointerGetDatum(PG_DETOAST_DATUM(var->value));
>> +                                     if (dvalue != var->value)
>> +                                     {
>> +                                             if (var->freeval)
>> +                                                     free_var(var);
>> +                                             var->value = dvalue;
>> +                                             var->freeval = true;
>> +                                     }
>> +                                     MemoryContextSwitchTo(oldcontext);
>
> This line adds trailing white space.
>
>> +                                     var->should_be_detoasted = false;
>> +                             }
>> +
>>                               *value = var->value;
>>                               *isnull = var->isnull;
>>                               break;
>
>> *** ./plpgsql.h.orig  2010-11-16 10:28:42.000000000 +0100
>> --- ./plpgsql.h       2010-11-22 13:12:38.897851879 +0100
>
>> ***************
>> *** 644,649 ****
>> --- 645,651 ----
>>       bool            fn_is_trigger;
>>       PLpgSQL_func_hashkey *fn_hashkey;       /* back-link to hashtable key 
>> */
>>       MemoryContext fn_cxt;
>> +     MemoryContext   fn_mcxt;                /* link to function's memory 
>> context */
>>
>>       Oid                     fn_rettype;
>>       int                     fn_rettyplen;
>> ***************
>> *** 692,697 ****
>> --- 694,701 ----
>>       Oid                     rettype;                /* type of current 
>> retval */
>>
>>       Oid                     fn_rettype;             /* info about declared 
>> function rettype */
>> +     MemoryContext   fn_mcxt;                /* link to function's memory 
>> context */
>> +
>>       bool            retistuple;
>>       bool            retisset;
>>
>
> I only see PLpgSQL_execstate.fn_mcxt getting populated in this patch.  Is the
> PLpgSQL_function.fn_mcxt leftover from an earlier design?

I have to access to top execution context from exec_eval_datum
function. This function can be called from parser's context, and
without explicit switch to top execution context a variables are
detoasted in wrong context.

>
> I could not readily tell the difference between fn_cxt and fn_mcxt.  As I
> understand it, fn_mcxt is the SPI procCxt, and fn_cxt is the long-lived 
> context
> used to cache facts across many transactions.  Perhaps name the member 
> something
> like "top_cxt", "exec_cxt" or "proc_cxt" and comment it like "/* SPI Proc 
> memory
> context */" to make this clearer.

I used a top_exec_cxt name

Pavel Stehule
Regards



>
*** ./src/pl/plpgsql/src/pl_exec.c.orig	2011-01-16 14:18:59.000000000 +0100
--- ./src/pl/plpgsql/src/pl_exec.c	2011-01-16 18:45:59.659254108 +0100
***************
*** 255,260 ****
--- 255,264 ----
  					var->value = fcinfo->arg[i];
  					var->isnull = fcinfo->argnull[i];
  					var->freeval = false;
+ 
+ 					/* only varlena types should be detoasted */
+ 					var->should_be_detoasted = !var->isnull && !var->datatype->typbyval
+ 											&& var->datatype->typlen == -1;
  				}
  				break;
  
***************
*** 570,581 ****
--- 574,587 ----
  		elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, UPDATE, or TRUNCATE");
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_name_varno]);
  	var->value = DirectFunctionCall1(namein,
  							  CStringGetDatum(trigdata->tg_trigger->tgname));
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_when_varno]);
  	if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
***************
*** 588,593 ****
--- 594,600 ----
  		elog(ERROR, "unrecognized trigger execution time: not BEFORE, AFTER, or INSTEAD OF");
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_level_varno]);
  	if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
***************
*** 598,620 ****
--- 605,631 ----
  		elog(ERROR, "unrecognized trigger event type: not ROW or STATEMENT");
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_relid_varno]);
  	var->value = ObjectIdGetDatum(trigdata->tg_relation->rd_id);
  	var->isnull = false;
  	var->freeval = false;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_relname_varno]);
  	var->value = DirectFunctionCall1(namein,
  			CStringGetDatum(RelationGetRelationName(trigdata->tg_relation)));
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_table_name_varno]);
  	var->value = DirectFunctionCall1(namein,
  			CStringGetDatum(RelationGetRelationName(trigdata->tg_relation)));
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_table_schema_varno]);
  	var->value = DirectFunctionCall1(namein,
***************
*** 624,634 ****
--- 635,647 ----
  												   trigdata->tg_relation))));
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_nargs_varno]);
  	var->value = Int16GetDatum(trigdata->tg_trigger->tgnargs);
  	var->isnull = false;
  	var->freeval = false;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_argv_varno]);
  	if (trigdata->tg_trigger->tgnargs > 0)
***************
*** 654,665 ****
--- 667,680 ----
  														-1, false, 'i'));
  		var->isnull = false;
  		var->freeval = true;
+ 		var->should_be_detoasted = false;
  	}
  	else
  	{
  		var->value = (Datum) 0;
  		var->isnull = true;
  		var->freeval = false;
+ 		var->should_be_detoasted = false;
  	}
  
  	estate.err_text = gettext_noop("during function entry");
***************
*** 841,846 ****
--- 856,862 ----
  				new->value = 0;
  				new->isnull = true;
  				new->freeval = false;
+ 				new->should_be_detoasted = false;
  
  				result = (PLpgSQL_datum *) new;
  			}
***************
*** 2652,2657 ****
--- 2668,2683 ----
  	estate->exitlabel = NULL;
  	estate->cur_error = NULL;
  
+ 	/*
+ 	 * Store a execution top memory context. The top context isn't usually
+ 	 * explicitly selected, but there is one exception. We would to detoast
+ 	 * datuns in this context. Varlena datums are explicitly detoasted in 
+ 	 * exec_eval_datum routine. This routine can be called from plpgsql_param_fetch,
+ 	 * what is callback for parser - etc different memory context, and then 
+ 	 * we have to access top execution memory context. 
+ 	 */
+ 	estate->top_exec_cxt = CurrentMemoryContext;
+ 
  	estate->tuple_store = NULL;
  	if (rsi)
  	{
***************
*** 3544,3550 ****
--- 3570,3579 ----
  				var->value = newvalue;
  				var->isnull = *isNull;
  				if (!var->datatype->typbyval && !*isNull)
+ 				{
  					var->freeval = true;
+ 					var->should_be_detoasted = var->datatype->typlen == -1;
+ 				}
  				break;
  			}
  
***************
*** 3944,3949 ****
--- 3973,4007 ----
  
  				*typeid = var->datatype->typoid;
  				*typetypmod = var->datatype->atttypmod;
+ 
+ 				/*
+ 				 * explicit deTOAST and decompress for varlena types
+ 				 */
+ 				if (var->should_be_detoasted)
+ 				{
+ 					Datum dvalue;
+ 
+ 					Assert(!var->isnull);
+ 
+ 					/*
+ 					 * We should to detoast variables in top execution context,
+ 					 * and then is necessary to switch to it (this routine
+ 					 * can be called from parser with different current 
+ 					 * context.
+ 					 */
+ 					oldcontext = MemoryContextSwitchTo(estate->top_exec_cxt);
+ 					dvalue = PointerGetDatum(PG_DETOAST_DATUM(var->value));
+ 					if (dvalue != var->value)
+ 					{
+ 						if (var->freeval)
+ 							free_var(var);
+ 						var->value = dvalue;
+ 						var->freeval = true;
+ 					}
+ 					MemoryContextSwitchTo(oldcontext); 
+ 					var->should_be_detoasted = false;
+ 				}
+ 
  				*value = var->value;
  				*isnull = var->isnull;
  				break;
***************
*** 5552,5557 ****
--- 5610,5616 ----
  	var->value = CStringGetTextDatum(str);
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  }
  
  /*
*** ./src/pl/plpgsql/src/plpgsql.h.orig	2011-01-16 14:18:59.000000000 +0100
--- ./src/pl/plpgsql/src/plpgsql.h	2011-01-16 18:41:54.104294898 +0100
***************
*** 242,247 ****
--- 242,248 ----
  	Datum		value;
  	bool		isnull;
  	bool		freeval;
+ 	bool		should_be_detoasted;
  } PLpgSQL_var;
  
  
***************
*** 643,649 ****
  	ItemPointerData fn_tid;
  	bool		fn_is_trigger;
  	PLpgSQL_func_hashkey *fn_hashkey;	/* back-link to hashtable key */
! 	MemoryContext fn_cxt;
  
  	Oid			fn_rettype;
  	int			fn_rettyplen;
--- 644,650 ----
  	ItemPointerData fn_tid;
  	bool		fn_is_trigger;
  	PLpgSQL_func_hashkey *fn_hashkey;	/* back-link to hashtable key */
! 	MemoryContext fn_cxt;			/* function's persistent context */
  
  	Oid			fn_rettype;
  	int			fn_rettyplen;
***************
*** 692,697 ****
--- 693,700 ----
  	Oid			rettype;		/* type of current retval */
  
  	Oid			fn_rettype;		/* info about declared function rettype */
+ 	MemoryContext	top_exec_cxt;			/* function's top execution memory context */
+ 
  	bool		retistuple;
  	bool		retisset;
  
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to