Changeset: 9cbea7bc661c for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=9cbea7bc661c Modified Files: gdk/gdk_join.c Branch: default Log Message:
Implemented specialized versions of mergejoin for int and lng. The most common set of options are fixed in these implementations. diffs (truncated from 632 to 300 lines): diff --git a/gdk/gdk_join.c b/gdk/gdk_join.c --- a/gdk/gdk_join.c +++ b/gdk/gdk_join.c @@ -1001,6 +1001,608 @@ mergejoin_void(BAT *r1, BAT *r2, BAT *l, * r; otherwise all matches are returned. */ static gdk_return +mergejoin_int(BAT *r1, BAT *r2, BAT *l, BAT *r, + int nil_matches, BUN maxsize, lng t0, int swapped) +{ + BUN lstart, lend; + BUN rstart, rend; + BUN lscan, rscan; /* opportunistic scan window */ + const int *lvals, *rvals; + int v; + BUN nl, nr; + oid lv; + BUN i; + + ALGODEBUG fprintf(stderr, "#mergejoin_int(l=%s#" BUNFMT "[%s]%s%s%s," + "r=%s#" BUNFMT "[%s]%s%s%s)%s\n", + BATgetId(l), BATcount(l), ATOMname(l->ttype), + l->tsorted ? "-sorted" : "", + l->trevsorted ? "-revsorted" : "", + l->tkey & 1 ? "-key" : "", + BATgetId(r), BATcount(r), ATOMname(r->ttype), + r->tsorted ? "-sorted" : "", + r->trevsorted ? "-revsorted" : "", + r->tkey & 1 ? "-key" : "", + swapped ? " swapped" : ""); + + assert(BAThdense(l)); + assert(BAThdense(r)); + assert(ATOMtype(l->ttype) == ATOMtype(r->ttype)); + assert(r->tsorted || r->trevsorted); + + lstart = rstart = 0; + lend = BATcount(l); + rend = BATcount(r); + lvals = (const int *) Tloc(l, BUNfirst(l)); + rvals = (const int *) Tloc(r, BUNfirst(r)); + assert(!r->tvarsized || !r->ttype); + + /* basic properties will be adjusted if necessary later on, + * they were initially set by joininitresults() */ + + if (lend == 0 || rend == 0) { + /* there are no matches */ + return nomatch(r1, r2, l, r, lstart, lend, NULL, NULL, + 0, 0, "mergejoin_int", t0); + } + + /* determine opportunistic scan window for l and r */ + for (nl = lend - lstart, lscan = 4; nl > 0; lscan++) + nl >>= 1; + for (nr = rend - rstart, rscan = 4; nr > 0; rscan++) + nr >>= 1; + + if (!nil_matches) { + /* skip over nils at the start of the columns */ + if (lscan < lend - lstart && lvals[lstart + lscan] == int_nil) { + lstart = binsearch_int(NULL, 0, lvals, lstart + lscan, + lend - 1, int_nil, 1, 1); + } else { + while (lvals[lstart] == int_nil) + lstart++; + } + if (rscan < rend - rstart && rvals[rstart + rscan] == int_nil) { + rstart = binsearch_int(NULL, 0, rvals, rstart + rscan, + rend - 1, int_nil, 1, 1); + } else { + while (rvals[rstart] == int_nil) + rstart++; + } + } + /* from here on we don't have to worry about nil values */ + + while (lstart < lend && rstart < rend) { + v = rvals[rstart]; + + if (lscan < lend - lstart && lvals[lstart + lscan] < v) { + lstart = binsearch_int(NULL, 0, lvals, lstart + lscan, + lend - 1, v, 1, 0); + } else { + /* scan l for v */ + while (lstart < lend && lvals[lstart] < v) + lstart++; + } + if (lstart >= lend) { + /* nothing found */ + break; + } + + /* Here we determine the next value in l that we are + * going to try to match in r. We will also count the + * number of occurrences in l of that value. + * Afterwards, v points to the value and nl is the + * number of times it occurs. Also, lstart will + * point to the next value to be considered (ready for + * the next iteration). + * If there are many equal values in l (more than + * lscan), we will use binary search to find the end + * of the sequence. Obviously, we can do this only if + * l is actually sorted (lscan > 0). */ + nl = 1; /* we'll match (at least) one in l */ + nr = 0; /* maybe we won't match anything in r */ + v = lvals[lstart]; + if (l->tkey) { + /* if l is key, there is a single value */ + lstart++; + } else if (lscan < lend - lstart && + v == lvals[lstart + lscan]) { + /* lots of equal values: use binary search to + * find end */ + nl = binsearch_int(NULL, 0, lvals, lstart + lscan, + lend - 1, v, 1, 1); + nl -= lstart; + lstart += nl; + } else { + /* just scan */ + while (++lstart < lend && v == lvals[lstart]) + nl++; + } + /* lstart points one beyond the value we're + * going to match: ready for the next iteration. */ + + /* First we find the first value in r that is at + * least as large as v, then we find the first + * value in r that is larger than v. The difference + * is the number of values equal to v and is stored in + * nr. + * We will use binary search on r to find both ends of + * the sequence of values that are equal to v in case + * the position is "too far" (more than rscan + * away). */ + + /* first find the location of the first value in r + * that is >= v, then find the location of the first + * value in r that is > v; the difference is the + * number of values equal to v */ + + /* look ahead a little (rscan) in r to see whether + * we're better off doing a binary search */ + if (rscan < rend - rstart && rvals[rstart + rscan] < v) { + /* value too far away in r: use binary + * search */ + rstart = binsearch_int(NULL, 0, rvals, rstart + rscan, + rend - 1, v, 1, 0); + } else { + /* scan r for v */ + while (rstart < rend && rvals[rstart] < v) + rstart++; + } + if (rstart == rend) { + /* nothing found */ + break; + } + + /* now find the end of the sequence of equal values v */ + + /* if r is key, there is zero or one match, otherwise + * look ahead a little (rscan) in r to see whether + * we're better off doing a binary search */ + if (r->tkey) { + if (rstart < rend && v == rvals[rstart]) { + nr = 1; + rstart++; + } + } else if (rscan < rend - rstart && + v == rvals[rstart + rscan]) { + /* range too large: use binary search */ + nr = binsearch_int(NULL, 0, rvals, rstart + rscan, + rend - 1, v, 1, 1); + nr -= rstart; + rstart += nr; + } else { + /* scan r for end of range */ + while (rstart < rend && v == rvals[rstart]) { + nr++; + rstart++; + } + } + /* rstart points to first value > v or end of + * r, and nr is the number of values in r that + * are equal to v */ + if (nr == 0) { + /* no entries in r found */ + continue; + } + /* make space: nl values in l match nr values in r, so + * we need to add nl * nr values in the results */ + if (BATcount(r1) + nl * nr > BATcapacity(r1)) { + /* make some extra space by extrapolating how + * much more we need (fraction of l we've seen + * so far is used as the fraction of the + * expected result size we've produced so + * far) */ + BUN newcap = (BUN) ((double) BATcount(l) / (BATcount(l) - (lend - lstart)) * (BATcount(r1) + nl * nr) * 1.1); + if (newcap < nl * nr + BATcount(r1)) + newcap = nl * nr + BATcount(r1) + 1024; + if (newcap > maxsize) + newcap = maxsize; + /* make sure heap.free is set properly before + * extending */ + BATsetcount(r1, BATcount(r1)); + if (BATextend(r1, newcap) != GDK_SUCCEED) + goto bailout; + BATsetcount(r2, BATcount(r2)); + if (BATextend(r2, newcap) != GDK_SUCCEED) + goto bailout; + assert(BATcapacity(r1) == BATcapacity(r2)); + } + + /* maintain properties */ + if (nl > 1) { + /* value occurs multiple times in l, so entry + * in r will be repeated multiple times: hence + * r2 is not key and not dense */ + r2->tkey = 0; + r2->tdense = 0; + /* multiple different values will be inserted + * in r1 (always in order), so not reverse + * ordered anymore */ + r1->trevsorted = 0; + } + if (nr > 1) { + /* value occurs multiple times in r, so entry + * in l will be repeated multiple times: hence + * r1 is not key and not dense */ + r1->tkey = 0; + r1->tdense = 0; + /* multiple different values will be inserted + * in r2 (in order), so not reverse ordered + * anymore */ + r2->trevsorted = 0; + if (nl > 1) { + /* multiple values in l match multiple + * values in r, so an ordered sequence + * will be inserted multiple times in + * r2, so r2 is not ordered anymore */ + r2->tsorted = 0; + } + } + if (BATcount(r1) > 0) { + /* a new, higher value will be inserted into + * r1, so r1 is not reverse ordered anymore */ + r1->trevsorted = 0; + /* a new higher value will be added to r2 */ + r2->trevsorted = 0; + if (r1->tdense && + ((oid *) r1->T->heap.base)[r1->batFirst + r1->batCount - 1] + 1 != l->hseqbase + lstart - nl) + r1->tdense = 0; + } + + if (BATcount(r2) > 0 && + r2->tdense && + ((oid *) r2->T->heap.base)[r2->batFirst + r2->batCount - 1] + 1 != r->hseqbase + rstart - nr) + r2->tdense = 0; + + /* insert values */ + lv = l->hseqbase + lstart - nl; + for (i = 0; i < nl; i++) { + BUN j; + oid rv; + + rv = r->hseqbase + rstart - nr; + for (j = 0; j < nr; j++) { + APPEND(r1, lv); + APPEND(r2, rv); + rv++; + } + lv++; + } + } + /* also set other bits of heap to correct value to indicate size */ + BATsetcount(r1, BATcount(r1)); + BATsetcount(r2, BATcount(r2)); + assert(BATcount(r1) == BATcount(r2)); + if (BATcount(r1) > 0) { + if (r1->tdense) + r1->tseqbase = ((oid *) r1->T->heap.base)[r1->batFirst]; + if (r2->tdense) + r2->tseqbase = ((oid *) r2->T->heap.base)[r2->batFirst]; + } + BATseqbase(r1, 0); + BATseqbase(r2, 0); + ALGODEBUG fprintf(stderr, "#mergejoin_int(l=%s,r=%s)=(%s#"BUNFMT"%s%s%s%s,%s#"BUNFMT"%s%s%s%s) " LLFMT "us\n", + BATgetId(l), BATgetId(r), + BATgetId(r1), BATcount(r1), + r1->tsorted ? "-sorted" : "", + r1->trevsorted ? "-revsorted" : "", + r1->tdense ? "-dense" : "", + r1->tkey & 1 ? "-key" : "", + BATgetId(r2), BATcount(r2), + r2->tsorted ? "-sorted" : "", + r2->trevsorted ? "-revsorted" : "", + r2->tdense ? "-dense" : "", + r2->tkey & 1 ? "-key" : "", + GDKusec() - t0); + return GDK_SUCCEED; _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list