Datum adaptive_merge_agg(PG_FUNCTION_ARGS) { AdaptiveCounter counter1; AdaptiveCounter counter2 = (AdaptiveCounter)PG_GETARG_BYTEA_P(1); /* is the counter created (if not, create it - error 1%, 10mil items) */ if (PG_ARGISNULL(0)) { /* just copy the second estimator into the first one */ counter1 = ac_copy(counter2); } else { /* ok, we already have the estimator - merge the second one into it */ counter1 = (AdaptiveCounter)PG_GETARG_BYTEA_P(0); /* perform the merge (in place) */ counter1 = ac_merge(counter1, counter2, true); } /* return the updated bytea */ PG_RETURN_BYTEA_P(counter1); }
/* Merge an adaptive counter into another one. The first parameter 'dest' is the target * counter that will be modified during the merge. * * The counters have to be 'the same' i.e. the basic parameters (level, length, itemSize * and error rate) need to be equal. */ AdaptiveCounter ac_merge(AdaptiveCounter dest, AdaptiveCounter src) { AdaptiveCounter result; int i = 0; /* check if we need to swap dest/src - we need the destination to have * higher (>=) level and lower item size (<=) at the same time */ if ((dest->level < src->level) || ((dest->level == src->level) && (dest->itemSize > src->itemSize))) { return ac_merge(src, dest); } /* it's possible to have (dest->level > src->level) and * (dest->itemSize > src->itemSize) at the same time, which makes * the counters impossible to merge. */ /* check that the counters are 'mergeable' - there are two * conditions: * * 1) Lower level has to be merged into the higher level (this is * assured thanks to the previous swap, so we have assert here). * * 2) The destination item size must not be higher than the source. * * Anyway the best way to make sure two counters are mergeable is * to use exactly the same counters (error rate, item length). * * Maybe there should be another condition on maxItems, but I don't * think so. */ assert(dest->level >= src->level); if (dest->itemSize > src->itemSize) { elog(ERROR, "counters not mergeable - item length dest=%d > src=%d ", dest->itemSize, src->itemSize); } /* allocate space for the destination counter (mergeable -> same size) */ result = ac_create_copy(dest); /* copy the items (from the src counter, the one with the lower level) */ for (i = 0; i < src->items; i++) { ac_add_hash(result, &(src->bitmap[i*src->itemSize])); } return result; }
Datum adaptive_merge_simple(PG_FUNCTION_ARGS) { AdaptiveCounter counter1 = (AdaptiveCounter)PG_GETARG_BYTEA_P(0); AdaptiveCounter counter2 = (AdaptiveCounter)PG_GETARG_BYTEA_P(1); /* is the counter created (if not, create it - error 1%, 10mil items) */ if (PG_ARGISNULL(0) && PG_ARGISNULL(1)) { PG_RETURN_NULL(); } else if (PG_ARGISNULL(0)) { PG_RETURN_BYTEA_P(ac_copy(counter2)); } else if (PG_ARGISNULL(1)) { PG_RETURN_BYTEA_P(ac_copy(counter1)); } else { PG_RETURN_BYTEA_P(ac_merge(counter1, counter2, false)); } }