Timezones handling changes:
authorFrantišek Dvořák <valtri@civ.zcu.cz>
Fri, 9 Apr 2010 10:37:54 +0000 (10:37 +0000)
committerFrantišek Dvořák <valtri@civ.zcu.cz>
Fri, 9 Apr 2010 10:37:54 +0000 (10:37 +0000)
- optimization, tzset() and TZ called only on month changes
- fixed returning TZ on platforms where setenv() has side effects
- test program (handy for the platform sensitive code)

org.glite.lb/configure
org.glite.lbjp-common.db/Makefile
org.glite.lbjp-common.db/configure
org.glite.lbjp-common.db/src/db.c
org.glite.lbjp-common.db/test/timezone.cpp [new file with mode: 0644]

index 71ff6f0..1c41dd1 100755 (executable)
@@ -330,7 +330,7 @@ BEGIN{
        'lb.harvester' => [ qw// ],
        'lb.yaim' => [ qw/yaim_core:R/ ],
        'lb.glite-LB' => [ qw/fetchcrl:R gpt:R gip_release:R gip_service:R bdii:R glite_version:R glite_info_templates:R glue_schema:R/ ],
-       'lbjp-common.db' => [ qw/mysql:B mysql-devel:B postgresql:B/ ],
+       'lbjp-common.db' => [ qw/mysql:B mysql-devel:B postgresql:B cppunit:B/ ],
        'lbjp-common.log' => [ qw/log4c/ ],
        'lbjp-common.maildir' => [ qw// ],
        'lbjp-common.server-bones' => [ qw// ],
index aa39082..0639deb 100644 (file)
@@ -21,7 +21,7 @@ version=${module.version}
 
 CC=gcc
 
-VPATH=${top_srcdir}/interface:${top_srcdir}/src:${top_srcdir}/examples
+VPATH=${top_srcdir}/interface:${top_srcdir}/src:${top_srcdir}/examples:${top_srcdir}/test
 
 DEBUG:=-g -O0 -W -Wall
 
@@ -65,7 +65,9 @@ TEST_INC:=-I${cppunit_prefix}/include
 LDFLAGS:=-L${stagedir}/${libdir} ${COVERAGE_FLAGS}
 
 COMPILE:=libtool --mode=compile ${CC} ${CFLAGS}
+COMPILEXX:=libtool --mode=compile ${CXX} ${CFLAGS}
 LINK:=libtool --mode=link ${CC} -rpath ${stagedir}/${libdir} ${LDFLAGS} 
+LINKXX:=libtool --mode=link ${CXX} -rpath ${stagedir}/${libdir} ${LDFLAGS} 
 INSTALL:=libtool --mode=install install
 
 EXT_LIBS:=-lglite_lbu_trio -lglite_lbu_log -lpthread ${DL_LIBS}
@@ -124,10 +126,13 @@ db_test_psql: db_test_psql.lo libglite_lbu_dbtest.la
 db_expire: db_expire.lo libglite_lbu_dbtest.la
        ${LINK} -o $@ $+ ${EXT_LIBS}
 
+timezone: timezone.lo libglite_lbu_db.la
+       ${LINKXX} -o $@ $+ ${TEST_LIBS} ${EXT_LIBS}
+
 compile: libglite_lbu_db.la
 
-check:
-       -echo No checks here yet.
+check: timezone
+       ./timezone
 
 test_coverage:
        -mkdir coverage
@@ -171,7 +176,7 @@ install: all
 clean:
        rm -rvf *.o *.lo *.loT .libs lib* *.c *.h *.dox C/ CPP/
        rm -rvf log.xml project/ rpmbuild/ RPMS/ tgz/
-       rm -rvf db_expire db_test db_test_mysql db_test_psql
+       rm -rvf db_expire db_test db_test_mysql db_test_psql timezone
 
 db-mysql.o db-mysql.lo: db-mysql.c
        ${COMPILE} ${MYSQL_CPPFLAGS} -c $<
@@ -185,6 +190,9 @@ db_test_mysql.o db_test_mysql.lo: db_test.c
 db_test_psql.o db_test_psql.lo: db_test.c
        ${COMPILE} -DPSQL_BACKEND=1 -c $< -o $@
 
+timezone.o timezone.lo: timezone.cpp
+       ${COMPILEXX} -c $< -o $@ ${TEST_INC}
+
 %.o %.lo: %.c
        ${COMPILE} -c $<
 
index 71ff6f0..1c41dd1 100755 (executable)
@@ -330,7 +330,7 @@ BEGIN{
        'lb.harvester' => [ qw// ],
        'lb.yaim' => [ qw/yaim_core:R/ ],
        'lb.glite-LB' => [ qw/fetchcrl:R gpt:R gip_release:R gip_service:R bdii:R glite_version:R glite_info_templates:R glue_schema:R/ ],
-       'lbjp-common.db' => [ qw/mysql:B mysql-devel:B postgresql:B/ ],
+       'lbjp-common.db' => [ qw/mysql:B mysql-devel:B postgresql:B cppunit:B/ ],
        'lbjp-common.log' => [ qw/log4c/ ],
        'lbjp-common.maildir' => [ qw// ],
        'lbjp-common.server-bones' => [ qw// ],
index 69705dd..095a28b 100644 (file)
@@ -132,41 +132,58 @@ void glite_lbu_TimestampToStr(double t, char **str) {
 }
 
 
+static time_t tm2time(struct tm *tm) {
+       static struct tm tm_last = { tm_year:0, tm_mon:0 };
+       static time_t t = (time_t)-1;
+       static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+       char *tz;
+
+       pthread_mutex_lock(&lock);
+       if (tm->tm_year == tm_last.tm_year && tm->tm_mon == tm_last.tm_mon) {
+               t = t + (tm->tm_sec - tm_last.tm_sec)
+                     + (tm->tm_min - tm_last.tm_min) * 60
+                     + (tm->tm_hour - tm_last.tm_hour) * 3600
+                     + (tm->tm_mday - tm_last.tm_mday) * 86400;
+               memcpy(&tm_last, tm, sizeof tm_last);
+       } else {
+               tz = getenv("TZ");
+               if (tz) tz = strdup(tz);
+               setenv("TZ", "UTC", 1);
+               tzset();
+
+               t =  mktime(tm);
+               memcpy(&tm_last, tm, sizeof tm_last);
+
+               if (tz) setenv("TZ", tz, 1);
+               else unsetenv("TZ");
+               free(tz);
+               tzset();
+       }
+       pthread_mutex_unlock(&lock);
+
+       return t;
+}
+
+
 time_t glite_lbu_StrToTime(const char *str) {
        struct tm       tm;
-       char *tz;
-       time_t t;
 
        memset(&tm,0,sizeof(tm));
-       tz = getenv("TZ");
-       setenv("TZ", "UTC", 1);
-       tzset();
-
        sscanf(str,"%4d-%02d-%02d %02d:%02d:%02d",
                &tm.tm_year,&tm.tm_mon,&tm.tm_mday,
                &tm.tm_hour,&tm.tm_min,&tm.tm_sec);
        tm.tm_year -= 1900;
        tm.tm_mon--;
-       t =  mktime(&tm);
-
-       if (tz) setenv("TZ", tz, 1);
-       else unsetenv("TZ");
-       tzset();
 
-       return t;
+       return tm2time(&tm);
 }
 
 
 double glite_lbu_StrToTimestamp(const char *str) {
        struct tm       tm;
-       double  sec, t;
-       char *tz;
+       double  sec;
 
        memset(&tm,0,sizeof(tm));
-       tz = getenv("TZ");
-       setenv("TZ", "UTC", 1);
-       tzset();
-
        sscanf(str,"%4d-%02d-%02d %02d:%02d:%lf",
                &tm.tm_year,&tm.tm_mon,&tm.tm_mday,
                &tm.tm_hour,&tm.tm_min,&sec);
@@ -174,13 +191,7 @@ double glite_lbu_StrToTimestamp(const char *str) {
        tm.tm_mon--;
        tm.tm_sec = sec;
 
-       t = (sec - tm.tm_sec) + mktime(&tm);
-
-       if (tz) setenv("TZ", tz, 1);
-       else unsetenv("TZ");
-       tzset();
-
-       return t;
+       return (sec - tm.tm_sec) + tm2time(&tm);
 }
 
 
diff --git a/org.glite.lbjp-common.db/test/timezone.cpp b/org.glite.lbjp-common.db/test/timezone.cpp
new file mode 100644 (file)
index 0000000..746bec5
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+See http://www.eu-egee.org/partners for details on the copyright holders.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#include <cstdlib>
+#include <cstring>
+#include <cstdio>
+#include <cmath>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+
+#include "db.h"
+
+#define zoneCheck(tmp) {\
+       (tmp) = getenv("TZ"); \
+       if (tz == NULL) CPPUNIT_ASSERT((tmp) == NULL);\
+       else CPPUNIT_ASSERT((tmp) != NULL && strcmp(tz, (tmp)) == 0);\
+}
+
+static struct {
+       time_t t;
+       const char *db;
+} data[] = {
+       // year of tiger (and day +, day -)
+       {t:1266142830, db:"2010-02-14 10:20:30"},
+       {t:1266142830-24*3600, db:"2010-02-13 10:20:30"},
+       {t:1266142830+24*3600, db:"2010-02-15 10:20:30"},
+
+       // two months later (and day +, day -)
+       {t:1271240430, db:"2010-04-14 10:20:30"},
+       {t:1271240430-24*3600, db:"2010-04-13 10:20:30"},
+       {t:1271240430+24*3600, db:"2010-04-15 10:20:30"},
+};
+
+class ZoneTest: public  CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(ZoneTest);
+       CPPUNIT_TEST(testInitialZoneCheck);
+       CPPUNIT_TEST(testTimeZone3);
+       CPPUNIT_TEST(testTimeZoneNULL);
+       CPPUNIT_TEST(testTimeZoneUTC);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+
+       void setUp() {
+               tz0 = getenv("TZ");
+       }
+
+       void tearDown() {
+               if (tz0) setenv("TZ", tz0, 1);
+               else unsetenv("TZ");
+       }
+
+       void testInitialZoneCheck() {
+               char *tz2;
+
+               zoneCheck(tz2);
+       }
+
+       void testTimeZone3() {
+               tz = "Tst 3:00";
+               setenv("TZ", tz, 1);
+               tzset();
+               testInitialZoneCheck();
+               convertCheck();
+       }
+
+       void testTimeZoneNULL() {
+               tz = NULL;
+               unsetenv("TZ");
+               tzset();
+               testInitialZoneCheck();
+               convertCheck();
+       }
+
+       void testTimeZoneUTC() {
+               tz = "UTC";
+               setenv("TZ", tz, 1);
+               tzset();
+               testInitialZoneCheck();
+               convertCheck();
+       }
+
+private:
+
+const char *tz0, *tz;
+
+void convertCheck() {
+       char *tz2;
+
+       time_t tt;
+       double st_d;
+       char *st_str, *st_dbstr, *t_dbstr;
+
+       char *s;
+       time_t t;
+       double d;
+       size_t i;
+
+       for (i = 0; i < sizeof(data)/sizeof(data[0]); i++) {
+               tt = data[i].t;
+               st_d = tt + 0.013;
+               asprintf(&t_dbstr, "'%s'", data[i].db);
+               asprintf(&st_str, "%s.013", data[i].db);
+               asprintf(&st_dbstr, "'%s.013'", data[i].db);
+
+               glite_lbu_TimeToStr(tt, &s);
+               CPPUNIT_ASSERT(s != NULL);
+               CPPUNIT_ASSERT(strcmp(s, t_dbstr) == 0);
+               free(s);
+               zoneCheck(tz2);
+
+               glite_lbu_TimestampToStr(st_d, &s);
+               CPPUNIT_ASSERT(s != NULL);
+               CPPUNIT_ASSERT(strncmp(s, st_dbstr, 24) == 0);
+               free(s);
+               zoneCheck(tz2);
+
+               t = glite_lbu_StrToTime(data[i].db);
+               CPPUNIT_ASSERT(t == tt);
+               zoneCheck(tz2);
+
+               d = glite_lbu_StrToTimestamp(st_str);
+               CPPUNIT_ASSERT(round(1000 * d) == round(1000 * st_d));
+               zoneCheck(tz2);
+
+               free(st_str);
+               free(st_dbstr);
+               free(t_dbstr);
+       }
+}
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( ZoneTest );
+
+int 
+main ()
+{
+       CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
+       CppUnit::TextUi::TestRunner runner;
+       
+       runner.addTest(suite);
+       return runner.run() ? 0 : 1;
+}