You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-11-03 17:13:17 +03:00
572 lines
13 KiB
C
572 lines
13 KiB
C
/** file: test.c - test of 64-bit integer stuff
|
|
*
|
|
*
|
|
* 21-jan-1998: David Perkins <dperkins@dsperkins.com>
|
|
*
|
|
*/
|
|
|
|
#include <net-snmp/net-snmp-config.h>
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
#if HAVE_WINSOCK_H
|
|
#include <winsock.h>
|
|
#endif
|
|
|
|
#include <net-snmp/types.h>
|
|
#include <net-snmp/library/int64.h>
|
|
#include <net-snmp/library/snmp_assert.h>
|
|
#include <net-snmp/library/snmp_debug.h>
|
|
#include <net-snmp/library/snmp_logging.h>
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
/** divBy10 - divide an unsigned 64-bit integer by 10
|
|
*
|
|
* call with:
|
|
* u64 - number to be divided
|
|
* pu64Q - location to store quotient
|
|
* puR - location to store remainder
|
|
*
|
|
*/
|
|
void
|
|
divBy10(U64 u64, U64 * pu64Q, unsigned int *puR)
|
|
{
|
|
unsigned long ulT;
|
|
unsigned long ulQ;
|
|
unsigned long ulR;
|
|
|
|
|
|
/*
|
|
* top 16 bits
|
|
*/
|
|
ulT = (u64.high >> 16) & 0x0ffff;
|
|
ulQ = ulT / 10;
|
|
ulR = ulT % 10;
|
|
pu64Q->high = ulQ << 16;
|
|
|
|
/*
|
|
* next 16
|
|
*/
|
|
ulT = (u64.high & 0x0ffff);
|
|
ulT += (ulR << 16);
|
|
ulQ = ulT / 10;
|
|
ulR = ulT % 10;
|
|
pu64Q->high = pu64Q->high | ulQ;
|
|
|
|
/*
|
|
* next 16
|
|
*/
|
|
ulT = ((u64.low >> 16) & 0x0ffff) + (ulR << 16);
|
|
ulQ = ulT / 10;
|
|
ulR = ulT % 10;
|
|
pu64Q->low = ulQ << 16;
|
|
|
|
/*
|
|
* final 16
|
|
*/
|
|
ulT = (u64.low & 0x0ffff);
|
|
ulT += (ulR << 16);
|
|
ulQ = ulT / 10;
|
|
ulR = ulT % 10;
|
|
pu64Q->low = pu64Q->low | ulQ;
|
|
|
|
*puR = (unsigned int) (ulR);
|
|
|
|
|
|
} /* divBy10 */
|
|
|
|
|
|
/** multBy10 - multiply an unsigned 64-bit integer by 10
|
|
*
|
|
* call with:
|
|
* u64 - number to be multiplied
|
|
* pu64P - location to store product
|
|
*
|
|
*/
|
|
void
|
|
multBy10(U64 u64, U64 * pu64P)
|
|
{
|
|
unsigned long ulT;
|
|
unsigned long ulP;
|
|
unsigned long ulK;
|
|
|
|
|
|
/*
|
|
* lower 16 bits
|
|
*/
|
|
ulT = u64.low & 0x0ffff;
|
|
ulP = ulT * 10;
|
|
ulK = ulP >> 16;
|
|
pu64P->low = ulP & 0x0ffff;
|
|
|
|
/*
|
|
* next 16
|
|
*/
|
|
ulT = (u64.low >> 16) & 0x0ffff;
|
|
ulP = (ulT * 10) + ulK;
|
|
ulK = ulP >> 16;
|
|
pu64P->low = (ulP & 0x0ffff) << 16 | pu64P->low;
|
|
|
|
/*
|
|
* next 16 bits
|
|
*/
|
|
ulT = u64.high & 0x0ffff;
|
|
ulP = (ulT * 10) + ulK;
|
|
ulK = ulP >> 16;
|
|
pu64P->high = ulP & 0x0ffff;
|
|
|
|
/*
|
|
* final 16
|
|
*/
|
|
ulT = (u64.high >> 16) & 0x0ffff;
|
|
ulP = (ulT * 10) + ulK;
|
|
ulK = ulP >> 16;
|
|
pu64P->high = (ulP & 0x0ffff) << 16 | pu64P->high;
|
|
|
|
|
|
} /* multBy10 */
|
|
|
|
|
|
/** incrByU16 - add an unsigned 16-bit int to an unsigned 64-bit integer
|
|
*
|
|
* call with:
|
|
* pu64 - number to be incremented
|
|
* u16 - amount to add
|
|
*
|
|
*/
|
|
void
|
|
incrByU16(U64 * pu64, unsigned int u16)
|
|
{
|
|
unsigned long ulT1;
|
|
unsigned long ulT2;
|
|
unsigned long ulR;
|
|
unsigned long ulK;
|
|
|
|
|
|
/*
|
|
* lower 16 bits
|
|
*/
|
|
ulT1 = pu64->low;
|
|
ulT2 = ulT1 & 0x0ffff;
|
|
ulR = ulT2 + u16;
|
|
ulK = ulR >> 16;
|
|
if (ulK == 0) {
|
|
pu64->low = ulT1 + u16;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* next 16 bits
|
|
*/
|
|
ulT2 = (ulT1 >> 16) & 0x0ffff;
|
|
ulR = ulT2 + 1;
|
|
ulK = ulR >> 16;
|
|
if (ulK == 0) {
|
|
pu64->low = ulT1 + u16;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* next 32 - ignore any overflow
|
|
*/
|
|
pu64->low = (ulT1 + u16) & 0x0FFFFFFFFL;
|
|
pu64->high++;
|
|
|
|
} /* incrByV16 */
|
|
|
|
void
|
|
incrByU32(U64 * pu64, unsigned int u32)
|
|
{
|
|
unsigned int tmp;
|
|
tmp = pu64->low;
|
|
pu64->low += u32;
|
|
if (pu64->low < tmp)
|
|
pu64->high++;
|
|
}
|
|
|
|
/**
|
|
* pu64out = pu64one - pu64two
|
|
*/
|
|
void
|
|
u64Subtract(const U64 * pu64one, const U64 * pu64two, U64 * pu64out)
|
|
{
|
|
if (pu64one->low < pu64two->low) {
|
|
pu64out->low = 0xffffffff - pu64two->low + pu64one->low + 1;
|
|
pu64out->high = pu64one->high - pu64two->high - 1;
|
|
} else {
|
|
pu64out->low = pu64one->low - pu64two->low;
|
|
pu64out->high = pu64one->high - pu64two->high;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* pu64out += pu64one
|
|
*/
|
|
void
|
|
u64Incr(U64 * pu64out, const U64 * pu64one)
|
|
{
|
|
pu64out->high += pu64one->high;
|
|
incrByU32(pu64out, pu64one->low);
|
|
}
|
|
|
|
/**
|
|
* pu64out += (pu64one - pu64two)
|
|
*/
|
|
void
|
|
u64UpdateCounter(U64 * pu64out, const U64 * pu64one, const U64 * pu64two)
|
|
{
|
|
U64 tmp;
|
|
u64Subtract(pu64one, pu64two, &tmp);
|
|
u64Incr(pu64out, &tmp);
|
|
}
|
|
|
|
/**
|
|
* pu64one = pu64two
|
|
*/
|
|
void
|
|
u64Copy(U64 * pu64one, const U64 * pu64two)
|
|
{
|
|
pu64one->high = pu64two->high;
|
|
pu64one->low = pu64two->low;
|
|
}
|
|
|
|
/** zeroU64 - set an unsigned 64-bit number to zero
|
|
*
|
|
* call with:
|
|
* pu64 - number to be zero'ed
|
|
*
|
|
*/
|
|
void
|
|
zeroU64(U64 * pu64)
|
|
{
|
|
|
|
pu64->low = 0;
|
|
pu64->high = 0;
|
|
} /* zeroU64 */
|
|
|
|
|
|
/** isZeroU64 - check if an unsigned 64-bit number is
|
|
*
|
|
* call with:
|
|
* pu64 - number to be zero'ed
|
|
*
|
|
*/
|
|
int
|
|
isZeroU64(const U64 * pu64)
|
|
{
|
|
|
|
if ((pu64->low == 0) && (pu64->high == 0))
|
|
return (TRUE);
|
|
else
|
|
return (FALSE);
|
|
|
|
} /* isZeroU64 */
|
|
|
|
/**
|
|
* check the old and new values of a counter64 for 32bit wrapping
|
|
*
|
|
* @param adjust : set to 1 to auto-increment new_val->high
|
|
* if a 32bit wrap is detected.
|
|
*
|
|
*@Note:
|
|
* The old and new values must be be from within a time period
|
|
* which would only allow the 32bit portion of the counter to
|
|
* wrap once. i.e. if the 32bit portion of the counter could
|
|
* wrap every 60 seconds, the old and new values should be compared
|
|
* at least every 59 seconds (though I'd recommend at least every
|
|
* 50 seconds to allow for timer inaccuracies).
|
|
*
|
|
* @retval 64 : 64bit wrap
|
|
* @retval 32 : 32bit wrap
|
|
* @retval 0 : did not wrap
|
|
* @retval -1 : bad parameter
|
|
* @retval -2 : unexpected high value (changed by more than 1)
|
|
*/
|
|
int
|
|
netsnmp_c64_check_for_32bit_wrap(struct counter64 *old_val,
|
|
struct counter64 *new_val,
|
|
int adjust)
|
|
{
|
|
if( (NULL == old_val) || (NULL == new_val) )
|
|
return -1;
|
|
|
|
DEBUGMSGTL(("9:c64:check_wrap", "check wrap 0x%0x.0x%0x 0x%0x.0x%0x\n",
|
|
old_val->high, old_val->low, new_val->high, new_val->low));
|
|
|
|
/*
|
|
* check for wraps
|
|
*/
|
|
if ((new_val->low >= old_val->low) &&
|
|
(new_val->high == old_val->high)) {
|
|
DEBUGMSGTL(("9:c64:check_wrap", "no wrap\n"));
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* low wrapped. did high change?
|
|
*/
|
|
if (new_val->high == old_val->high) {
|
|
DEBUGMSGTL(("c64:check_wrap", "32 bit wrap\n"));
|
|
if (adjust)
|
|
++new_val->high;
|
|
return 32;
|
|
}
|
|
else if ((new_val->high == (old_val->high + 1)) ||
|
|
((0 == new_val->high) && (0xffffffff == old_val->high))) {
|
|
DEBUGMSGTL(("c64:check_wrap", "64 bit wrap\n"));
|
|
return 64;
|
|
}
|
|
|
|
return -2;
|
|
}
|
|
|
|
/**
|
|
* update a 64 bit value with the difference between two (possibly) 32 bit vals
|
|
*
|
|
* @param prev_val : the 64 bit current counter
|
|
* @param old_prev_val : the (possibly 32 bit) previous value
|
|
* @param new_val : the (possible 32bit) new value
|
|
* @param need_wrap_check: pointer to integer indicating if wrap check is needed
|
|
* flag may be cleared if 64 bit counter is detected
|
|
*
|
|
*@Note:
|
|
* The old_prev_val and new_val values must be be from within a time
|
|
* period which would only allow the 32bit portion of the counter to
|
|
* wrap once. i.e. if the 32bit portion of the counter could
|
|
* wrap every 60 seconds, the old and new values should be compared
|
|
* at least every 59 seconds (though I'd recommend at least every
|
|
* 50 seconds to allow for timer inaccuracies).
|
|
*
|
|
* Suggested use:
|
|
*
|
|
* static needwrapcheck = 1;
|
|
* static counter64 current, prev_val, new_val;
|
|
*
|
|
* your_functions_to_update_new_value(&new_val);
|
|
* if (0 == needwrapcheck)
|
|
* memcpy(current, new_val, sizeof(new_val));
|
|
* else {
|
|
* netsnmp_c64_check32_and_update(¤t,&new,&prev,&needwrapcheck);
|
|
* memcpy(prev_val, new_val, sizeof(new_val));
|
|
* }
|
|
*
|
|
*
|
|
* @retval 0 : success
|
|
* @retval -1 : error checking for 32 bit wrap
|
|
* @retval -2 : look like we have 64 bit values, but sums aren't consistent
|
|
*/
|
|
int
|
|
netsnmp_c64_check32_and_update(struct counter64 *prev_val, struct counter64 *new_val,
|
|
struct counter64 *old_prev_val, int *need_wrap_check)
|
|
{
|
|
int rc;
|
|
|
|
/*
|
|
* counters are 32bit or unknown (which we'll treat as 32bit).
|
|
* update the prev values with the difference between the
|
|
* new stats and the prev old_stats:
|
|
* prev->stats += (new->stats - prev->old_stats)
|
|
*/
|
|
if ((NULL == need_wrap_check) || (0 != *need_wrap_check)) {
|
|
rc = netsnmp_c64_check_for_32bit_wrap(old_prev_val,new_val, 1);
|
|
if (rc < 0) {
|
|
snmp_log(LOG_ERR,"c64 32 bit check failed\n");
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
rc = 0;
|
|
|
|
/*
|
|
* update previous values
|
|
*/
|
|
(void) u64UpdateCounter(prev_val, new_val, old_prev_val);
|
|
|
|
/*
|
|
* if wrap check was 32 bit, undo adjust, now that prev is updated
|
|
*/
|
|
if (32 == rc) {
|
|
/*
|
|
* check wrap incremented high, so reset it. (Because having
|
|
* high set for a 32 bit counter will confuse us in the next update).
|
|
*/
|
|
netsnmp_assert(1 == new_val->high);
|
|
new_val->high = 0;
|
|
}
|
|
else if (64 == rc) {
|
|
/*
|
|
* if we really have 64 bit counters, the summing we've been
|
|
* doing for prev values should be equal to the new values.
|
|
*/
|
|
if ((prev_val->low != new_val->low) ||
|
|
(prev_val->high != new_val->high)) {
|
|
snmp_log(LOG_ERR, "looks like a 64bit wrap, but prev!=new\n");
|
|
return -2;
|
|
}
|
|
else if (NULL != need_wrap_check)
|
|
*need_wrap_check = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
printU64(char *buf, /* char [I64CHARSZ+1]; */
|
|
const U64 * pu64) {
|
|
U64 u64a;
|
|
U64 u64b;
|
|
|
|
char aRes[I64CHARSZ + 1];
|
|
unsigned int u;
|
|
int j;
|
|
|
|
u64a.high = pu64->high;
|
|
u64a.low = pu64->low;
|
|
aRes[I64CHARSZ] = 0;
|
|
for (j = 0; j < I64CHARSZ; j++) {
|
|
divBy10(u64a, &u64b, &u);
|
|
aRes[(I64CHARSZ - 1) - j] = (char) ('0' + u);
|
|
u64a.high = u64b.high;
|
|
u64a.low = u64b.low;
|
|
if (isZeroU64(&u64a))
|
|
break;
|
|
}
|
|
strcpy(buf, &aRes[(I64CHARSZ - 1) - j]);
|
|
}
|
|
|
|
void
|
|
printI64(char *buf, /* char [I64CHARSZ+1]; */
|
|
const U64 * pu64) {
|
|
U64 u64a;
|
|
U64 u64b;
|
|
|
|
char aRes[I64CHARSZ + 1];
|
|
unsigned int u;
|
|
int j, sign = 0;
|
|
|
|
if (pu64->high & 0x80000000) {
|
|
u64a.high = ~pu64->high;
|
|
u64a.low = ~pu64->low;
|
|
sign = 1;
|
|
incrByU32(&u64a, 1); /* bit invert and incr by 1 to print 2s complement */
|
|
} else {
|
|
u64a.high = pu64->high;
|
|
u64a.low = pu64->low;
|
|
}
|
|
|
|
aRes[I64CHARSZ] = 0;
|
|
for (j = 0; j < I64CHARSZ; j++) {
|
|
divBy10(u64a, &u64b, &u);
|
|
aRes[(I64CHARSZ - 1) - j] = (char) ('0' + u);
|
|
u64a.high = u64b.high;
|
|
u64a.low = u64b.low;
|
|
if (isZeroU64(&u64a))
|
|
break;
|
|
}
|
|
if (sign == 1) {
|
|
aRes[(I64CHARSZ - 1) - j - 1] = '-';
|
|
strcpy(buf, &aRes[(I64CHARSZ - 1) - j - 1]);
|
|
return;
|
|
}
|
|
strcpy(buf, &aRes[(I64CHARSZ - 1) - j]);
|
|
}
|
|
|
|
int
|
|
read64(U64 * i64, const char *string)
|
|
{
|
|
U64 i64p;
|
|
unsigned int u;
|
|
int sign = 0;
|
|
int ok = 0;
|
|
|
|
zeroU64(i64);
|
|
if (*string == '-') {
|
|
sign = 1;
|
|
string++;
|
|
}
|
|
|
|
while (*string && isdigit(*string)) {
|
|
ok = 1;
|
|
u = *string - '0';
|
|
multBy10(*i64, &i64p);
|
|
memcpy(i64, &i64p, sizeof(i64p));
|
|
incrByU16(i64, u);
|
|
string++;
|
|
}
|
|
if (sign) {
|
|
i64->high = ~i64->high;
|
|
i64->low = ~i64->low;
|
|
incrByU16(i64, 1);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef TESTING
|
|
void
|
|
main(int argc, char *argv[])
|
|
{
|
|
int i;
|
|
int j;
|
|
int l;
|
|
unsigned int u;
|
|
U64 u64a;
|
|
U64 u64b;
|
|
#define MXSZ 20
|
|
char aRes[MXSZ + 1];
|
|
|
|
|
|
if (argc < 2) {
|
|
printf("This program takes numbers from the command line\n"
|
|
"and prints them out.\n" "Usage: test <unsignedInt>...\n");
|
|
exit(1);
|
|
}
|
|
|
|
aRes[MXSZ] = 0;
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
l = strlen(argv[i]);
|
|
zeroU64(&u64a);
|
|
for (j = 0; j < l; j++) {
|
|
if (!isdigit(argv[i][j])) {
|
|
printf("Argument is not a number \"%s\"\n", argv[i]);
|
|
exit(1);
|
|
}
|
|
u = argv[i][j] - '0';
|
|
multBy10(u64a, &u64b);
|
|
u64a = u64b;
|
|
incrByU16(&u64a, u);
|
|
}
|
|
|
|
printf("number \"%s\" in hex is '%08x%08x'h\n",
|
|
argv[i], u64a.high, u64a.low);
|
|
|
|
printf("number is \"%s\"\n", printU64(&u64a));
|
|
for (j = 0; j < MXSZ; j++) {
|
|
divBy10(u64a, &u64b, &u);
|
|
aRes[(MXSZ - 1) - j] = (char) ('0' + u);
|
|
u64a = u64b;
|
|
if (isZeroU64(&u64a))
|
|
break;
|
|
}
|
|
|
|
printf("number is \"%s\"\n", &aRes[(MXSZ - 1) - j]);
|
|
}
|
|
exit(0);
|
|
} /* main */
|
|
#endif /* TESTING */
|
|
|
|
/*
|
|
* file: test.c
|
|
*/
|