Changeset: 89a284108096 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=89a284108096 Modified Files: gdk/gdk.h gdk/gdk_bbp.c gdk/gdk_logger.c gdk/gdk_logger.h gdk/gdk_private.h monetdb5/modules/atoms/mtime.c monetdb5/modules/atoms/mtime.h Branch: mtime Log Message:
Changed internal representation of the date type. The internal representation now consists of a number of months since an epoch and separately the day within that month. diffs (truncated from 1274 to 300 lines): diff --git a/gdk/gdk.h b/gdk/gdk.h --- a/gdk/gdk.h +++ b/gdk/gdk.h @@ -778,7 +778,8 @@ typedef struct { #define GDKLIBRARY_TALIGN 061036U /* talign field in BBP.dir */ #define GDKLIBRARY_NIL_NAN 061037U /* flt/dbl NIL not represented by NaN */ #define GDKLIBRARY_BLOB_SORT 061040U /* blob compare changed */ -#define GDKLIBRARY 061041U +#define GDKLIBRARY_OLDDATE 061041U +#define GDKLIBRARY 061042U typedef struct BAT { /* static bat properties */ diff --git a/gdk/gdk_bbp.c b/gdk/gdk_bbp.c --- a/gdk/gdk_bbp.c +++ b/gdk/gdk_bbp.c @@ -586,6 +586,267 @@ fixfloatbats(void) } #endif +#ifdef GDKLIBRARY_OLDDATE +#define leapyear(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0)) +#define YEARDAYS(y) (leapyear(y) ? 366 : 365) +static int CUMLEAPDAYS[13] = { + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 +}; +static int CUMDAYS[13] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 +}; +static int +leapyears(int year) +{ + /* count the 4-fold years that passed since jan-1-0 */ + int y4 = year / 4; + + /* count the 100-fold years */ + int y100 = year / 100; + + /* count the 400-fold years */ + int y400 = year / 400; + + return y4 + y400 - y100 + (year >= 0); /* may be negative */ +} + +#define YEAR_OFFSET 4712 +#define DTDAY_WIDTH 5 /* 1..28/29/30/31, depending on month */ +#define DTDAY_SHIFT 0 +#define DTMONTH_WIDTH 21 /* enough for 174762 year */ +#define DTMONTH_SHIFT (DTDAY_WIDTH+DTDAY_SHIFT) +#define mkdate(d, m, y) (((((y) + YEAR_OFFSET) * 12 + (m) - 1) << DTMONTH_SHIFT) \ + | ((d) << DTDAY_SHIFT)) +int +cvtdate(int n) +{ + int day, month, year; + + year = n / 365; + day = (n - year * 365) - leapyears(year >= 0 ? year - 1 : year); + if (n < 0) { + year--; + while (day >= 0) { + year++; + day -= YEARDAYS(year); + } + day = YEARDAYS(year) + day; + } else { + while (day < 0) { + year--; + day += YEARDAYS(year); + } + } + + day++; + if (leapyear(year)) { + for (month = day / 31 == 0 ? 1 : day / 31; month <= 12; month++) + if (day > CUMLEAPDAYS[month - 1] && day <= CUMLEAPDAYS[month]) { + break; + } + day -= CUMLEAPDAYS[month - 1]; + } else { + for (month = day / 31 == 0 ? 1 : day / 31; month <= 12; month++) + if (day > CUMDAYS[month - 1] && day <= CUMDAYS[month]) { + break; + } + day -= CUMDAYS[month - 1]; + } + /* clamp date */ + if (year < -YEAR_OFFSET) { + day = 1; + month = 1; + year = -YEAR_OFFSET; + } else if (year > ((1<<21)/12 - YEAR_OFFSET)) { + day = 31; + month = 12; + year = (1<<21)/12 - YEAR_OFFSET; + } + return mkdate(day, month, year); +} + +static gdk_return +fixdateheap(BAT *b, const char *anme) +{ + long_str filename; + Heap h1; /* old heap */ + Heap h2; /* new heap */ + const char *nme, *bnme; + char *srcdir; + BUN i; + bool nofix = true; + + nme = BBP_physical(b->batCacheid); + srcdir = GDKfilepath(NOFARM, BATDIR, nme, NULL); + if (srcdir == NULL) { + return GDK_FAIL; + } + *strrchr(srcdir, DIR_SEP) = 0; + + if ((bnme = strrchr(nme, DIR_SEP)) != NULL) + bnme++; + else + bnme = nme; + sprintf(filename, "BACKUP%c%s", DIR_SEP, bnme); + + /* make backup of heap */ + if (GDKmove(b->theap.farmid, srcdir, bnme, "tail", BAKDIR, bnme, "tail") != GDK_SUCCEED) { + GDKfree(srcdir); + GDKerror("fixdateheap: cannot make backup of %s.tail\n", nme); + return GDK_FAIL; + } + /* load old heap */ + h1 = b->theap; + stpconcat(h1.filename, filename, ".tail", NULL); + h1.base = NULL; + h1.dirty = false; + if (HEAPload(&h1, filename, "tail", false) != GDK_SUCCEED) { + GDKfree(srcdir); + GDKerror("fixdateheap: loading old tail heap " + "for BAT %d failed\n", b->batCacheid); + return GDK_FAIL; + } + + /* create new heap */ + h2 = b->theap; + stpconcat(h2.filename, nme, ".tail", NULL); + if (HEAPalloc(&h2, b->batCapacity, b->twidth) != GDK_SUCCEED) { + GDKfree(srcdir); + HEAPfree(&h1, false); + GDKerror("fixdateheap: allocating new tail heap " + "for BAT %d failed\n", b->batCacheid); + return GDK_FAIL; + } + h2.dirty = true; + h2.free = h1.free; + + if (strcmp(anme, "date") == 0) { + const int *restrict o = (const int *) h1.base; + int *restrict n = (int *) h2.base; + + for (i = 0; i < b->batCount; i++) { + if (is_int_nil(o[i])) { + b->tnil = true; + n[i] = int_nil; + } else { + n[i] = cvtdate(o[i]); + nofix = false; + } + } + } else { + union timestamp { + lng l; + struct { +#ifndef WORDS_BIGENDIAN + int p_msecs; + int p_days; +#else + int p_days; + int p_msecs; +#endif + } t; + }; + const union timestamp *restrict o = (const union timestamp *) h1.base; + union timestamp *restrict n = (union timestamp *) h2.base; + for (i = 0; i < b->batCount; i++) { + if (is_lng_nil(o[i].l)) { + b->tnil = true; + n[i].l = lng_nil; + } else { + n[i].t.p_days = cvtdate(o[i].t.p_days); + n[i].t.p_msecs = o[i].t.p_msecs; + nofix = false; + } + } + } + + /* cleanup */ + HEAPfree(&h1, false); + if (nofix) { + /* didn't fix anything, move backup back */ + HEAPfree(&h2, true); + if (GDKmove(b->theap.farmid, BAKDIR, bnme, "tail", srcdir, bnme, "tail") != GDK_SUCCEED) { + GDKfree(srcdir); + GDKerror("fixdateheap: cannot restore backup of %s.tail\n", nme); + return GDK_FAIL; + } + } else { + /* heap was fixed */ + b->batDirtydesc = true; + if (HEAPsave(&h2, nme, "tail") != GDK_SUCCEED) { + HEAPfree(&h2, false); + GDKfree(srcdir); + GDKerror("fixdateheap: saving heap failed\n"); + return GDK_FAIL; + } + HEAPfree(&h2, false); + b->theap = h2; + } + GDKfree(srcdir); + return GDK_SUCCEED; +} + +static gdk_return +fixdatebats(void) +{ + bat bid; + BAT *b; + char filename[FILENAME_MAX]; + FILE *fp; + size_t len; + int written; + + for (bid = 1; bid < (bat) ATOMIC_GET(&BBPsize); bid++) { + if ((b = BBP_desc(bid)) == NULL) { + /* not a valid BAT */ + continue; + } + if (BBP_logical(bid) && + (len = strlen(BBP_logical(bid))) > 12 && + strcmp(BBP_logical(bid) + len - 12, "_catalog_nme") == 0) { + /* this is one of the files used by the + * logger. We need to communicate to the + * logger that it also needs to do a + * conversion. That is done by creating a + * file here based on the name of this BAT. */ + written = snprintf(filename, sizeof(filename), + "%s/%.*s_date-convert", + BBPfarms[0].dirname, + (int) (len - 12), BBP_logical(bid)); + if (written == -1 || written >= FILENAME_MAX) { + GDKerror("fixdatebats: cannot create file %s has a very large pathname\n", + filename); + return GDK_FAIL; + } + fp = fopen(filename, "w"); + if (fp == NULL) { + GDKsyserror("fixdatebats: cannot create file %s\n", + filename); + return GDK_FAIL; + } + fclose(fp); + } + if (b->batCount == 0 || b->tnonil) { + /* no NILs to convert */ + continue; + } + /* The date type is not known in GDK when reading the BBP */ + if (b->ttype < 0) { + const char *anme; + + /* as yet unknown tail column type */ + anme = ATOMunknown_name(b->ttype); + /* known string types */ + if ((strcmp(anme, "date") == 0 || + strcmp(anme, "timestamp") == 0) && + fixdateheap(b, anme) != GDK_SUCCEED) + return GDK_FAIL; + } + } + return GDK_SUCCEED; +} +#endif + static int heapinit(BAT *b, const char *buf, int *hashash, unsigned bbpversion, bat bid, const char *filename) { @@ -1250,6 +1511,11 @@ BBPinit(void) if (fixfloatbats() != GDK_SUCCEED) return GDK_FAIL; #endif +#ifdef GDKLIBRARY_OLDDATE + if (bbpversion <= GDKLIBRARY_OLDDATE) + if (fixdatebats() != GDK_SUCCEED) + return GDK_FAIL; +#endif if (bbpversion < GDKLIBRARY) TMcommit(); return GDK_SUCCEED; diff --git a/gdk/gdk_logger.c b/gdk/gdk_logger.c --- a/gdk/gdk_logger.c +++ b/gdk/gdk_logger.c @@ -400,6 +400,47 @@ mbrRead(void *dst, stream *s, size_t cnt _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list