microseconds in CSNs. Omit microseconds from modifyTImestamp...
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 ));
#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 );
* 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().
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;
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
+#ifdef _WIN32
+#include <windows.h>
+#endif
#include "lutil.h"
#include "ldap_defaults.h"
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.
#endif
#ifdef _MSC_VER
-#include <windows.h>
struct dirent {
char *d_name;
};
static char time_unit[] = "dhms";
+/* Used to parse and unparse time intervals, not timestamps */
int
lutil_parse_time(
const char *in,
}
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();
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 {