From 4b1bb81452c7dc08c6099fc06d84c380cb41c7c0 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Fri, 2 Feb 2007 23:10:30 +0000 Subject: [PATCH] Add lutil_gettime() returning structured time with microseconds. Use microseconds in CSNs. Omit microseconds from modifyTImestamp... --- include/lutil.h | 7 +++ libraries/liblutil/csn.c | 31 ++++++-------- libraries/liblutil/utils.c | 88 +++++++++++++++++++++++++++++++++++++- servers/slapd/add.c | 5 +-- servers/slapd/modify.c | 6 +-- 5 files changed, 110 insertions(+), 27 deletions(-) diff --git a/include/lutil.h b/include/lutil.h index 6b2bf76bef..c5b9c528cf 100644 --- a/include/lutil.h +++ b/include/lutil.h @@ -166,14 +166,20 @@ typedef struct lutil_timet { unsigned int tt_usec; /* microseconds */ } lutil_timet; +/* Parse a timestamp string into a structure */ LDAP_LUTIL_F( int ) lutil_parsetime LDAP_P(( char *atm, struct lutil_tm * )); +/* Convert structured time to time in seconds since 1900 */ LDAP_LUTIL_F( int ) lutil_tm2time LDAP_P(( struct lutil_tm *, struct lutil_timet * )); +/* Get current time as a structured time */ +LDAP_LUTIL_F( void ) +lutil_gettime LDAP_P(( struct lutil_tm * )); + #ifdef _WIN32 LDAP_LUTIL_F( void ) lutil_slashpath LDAP_P(( char* path )); @@ -290,6 +296,7 @@ lutil_atoulx( unsigned long *v, const char *s, int x ); #define lutil_atol(v, s) lutil_atolx((v), (s), 10) #define lutil_atoul(v, s) lutil_atoulx((v), (s), 10) +/* Parse and unparse time intervals */ LDAP_LUTIL_F (int) lutil_parse_time( const char *in, unsigned long *tp ); diff --git a/libraries/liblutil/csn.c b/libraries/liblutil/csn.c index 51683f0466..647eabe4ec 100644 --- a/libraries/liblutil/csn.c +++ b/libraries/liblutil/csn.c @@ -35,8 +35,8 @@ * where s is a counter of operations within a timeslice, r is * the replica id (normally zero), and c is a counter of * modifications within this operation. s, r, and c are - * represented in hex and zero padded to lengths of 6, 2, and - * 6, respectively. + * represented in hex and zero padded to lengths of 6, 3, and + * 6, respectively. (In previous implementations r was only 2 digits.) * * Calls to this routine MUST be serialized with other calls * to gmtime(). @@ -51,33 +51,26 @@ size_t lutil_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod) { - static time_t csntime; + struct lutil_tm tm; static unsigned int csnop; + static int prev_sec, prev_usec; - time_t t; unsigned int op; - struct tm *ltm; -#ifdef HAVE_GMTIME_R - struct tm ltm_buf; -#endif int n; - time( &t ); - if ( t > csntime ) { - csntime = t; + lutil_gettime( &tm ); + + if ( tm.tm_usec != prev_usec || tm.tm_sec != prev_sec ) { + prev_sec = tm.tm_sec; + prev_usec = tm.tm_usec; csnop = 0; } op = csnop++; -#ifdef HAVE_GMTIME_R - ltm = gmtime_r( &t, <m_buf ); -#else - ltm = gmtime( &t ); -#endif n = snprintf( buf, len, - "%4d%02d%02d%02d%02d%02dZ#%06x#%02x#%06x", - ltm->tm_year + 1900, ltm->tm_mon + 1, ltm->tm_mday, ltm->tm_hour, - ltm->tm_min, ltm->tm_sec, op, replica, mod ); + "%4d%02d%02d%02d%02d%02d.%06dZ#%06x#%03x#%06x", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec, tm.tm_usec, op, replica, mod ); if( n < 0 ) return 0; return ( (size_t) n < len ) ? n : 0; diff --git a/libraries/liblutil/utils.c b/libraries/liblutil/utils.c index 96271b4e1e..ee69a1baf0 100644 --- a/libraries/liblutil/utils.c +++ b/libraries/liblutil/utils.c @@ -27,6 +27,9 @@ #ifdef HAVE_FCNTL_H #include #endif +#ifdef _WIN32 +#include +#endif #include "lutil.h" #include "ldap_defaults.h" @@ -269,6 +272,89 @@ int lutil_parsetime( char *atm, struct lutil_tm *tm ) return -1; } +/* return a broken out time, with microseconds */ +#ifdef _WIN32 +/* Windows SYSTEMTIME only has 10 millisecond resolution, so we + * also need to use a high resolution timer to get microseconds. + * This is pretty clunky. + */ +void +lutil_gettime( struct lutil_tm *tm ) +{ + static LARGE_INTEGER cFreq; + static int offset; + LARGE_INTEGER count; + SYSTEMTIME st; + + GetSystemTime( &st ); + QueryPerformanceCounter( &count ); + + /* We assume Windows has at least a vague idea of + * when a second begins. So we align our microsecond count + * with the Windows millisecond count using this offset. + * We retain the submillisecond portion of our own count. + */ + if ( !cFreq.QuadPart ) { + long long t; + int usec; + QueryPerformanceFrequency( &cFreq ); + + t = count.QuadPart * 1000000; + t /= cFreq.QuadPart; + usec = t % 10000000; + usec /= 1000; + offset = ( usec - st.wMilliseconds ) * 1000; + } + + /* convert to microseconds */ + count.QuadPart *= 1000000; + count.QuadPart /= cFreq.QuadPart; + count.QuadPart -= offset; + + tm->tm_usec = count.QuadPart % 1000000; + printf("tm_usec %d, msec %d\n", tm->tm_usec, st.wMilliseconds); + + /* any difference larger than microseconds is + * already reflected in st + */ + + tm->tm_sec = st.wSecond; + tm->tm_min = st.wMinute; + tm->tm_hour = st.wHour; + tm->tm_mday = st.wDay; + tm->tm_mon = st.wMonth - 1; + tm->tm_year = st.wYear - 1900; +} +#else +void +lutil_gettime( struct lutil_tm *ltm ) +{ + struct timeval tv; +#ifdef HAVE_GMTIME_R + struct tm tm_buf; +#endif + struct tm *tm; + time_t t; + + gettimeofday( &tv, NULL ); + t = tv.tv_sec; + +#ifdef HAVE_GMTIME_R + tm = gmtime_r( &t, &tm_buf ); +#else + tm = gmtime( &t ); +#endif + + ltm->tm_sec = tm->tm_sec; + ltm->tm_min = tm->tm_min; + ltm->tm_hour = tm->tm_hour; + ltm->tm_mday = tm->tm_mday; + ltm->tm_mon = tm->tm_mon; + ltm->tm_year = tm->tm_year; + ltm->tm_usec = tv.tv_usec; +} +#endif + /* strcopy is like strcpy except it returns a pointer to the trailing NUL of * the result string. This allows fast construction of catenated strings * without the overhead of strlen/strcat. @@ -316,7 +402,6 @@ int mkstemp( char * template ) #endif #ifdef _MSC_VER -#include struct dirent { char *d_name; }; @@ -491,6 +576,7 @@ lutil_atoulx( unsigned long *v, const char *s, int x ) static char time_unit[] = "dhms"; +/* Used to parse and unparse time intervals, not timestamps */ int lutil_parse_time( const char *in, diff --git a/servers/slapd/add.c b/servers/slapd/add.c index db9b809752..8d22d54afc 100644 --- a/servers/slapd/add.c +++ b/servers/slapd/add.c @@ -608,10 +608,9 @@ int slap_add_opattrs( } ptr = ber_bvchr( &csn, '#' ); if ( ptr ) { - timestamp.bv_len = ptr - csn.bv_val; - if ( timestamp.bv_len >= sizeof(timebuf) ) /* ?!? */ - timestamp.bv_len = sizeof(timebuf) - 1; + timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ"); AC_MEMCPY( timebuf, csn.bv_val, timestamp.bv_len ); + timebuf[timestamp.bv_len-1] = 'Z'; timebuf[timestamp.bv_len] = '\0'; } else { time_t now = slap_get_time(); diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c index ca53e0b9fa..0cd1d039ab 100644 --- a/servers/slapd/modify.c +++ b/servers/slapd/modify.c @@ -924,11 +924,9 @@ void slap_mods_opattrs( ptr = ber_bvchr( &csn, '#' ); if ( ptr ) { - timestamp.bv_len = ptr - csn.bv_val; - if ( timestamp.bv_len >= sizeof( timebuf ) ) { /* ?!? */ - timestamp.bv_len = sizeof( timebuf ) - 1; - } + timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ"); AC_MEMCPY( timebuf, csn.bv_val, timestamp.bv_len ); + timebuf[timestamp.bv_len-1] = 'Z'; timebuf[timestamp.bv_len] = '\0'; } else { -- 2.39.5