btcollider/bf/hsearchf.c
2018-04-04 15:18:34 +02:00

97 lines
2.5 KiB
C

/* Copyright (c) 2015 Ryan Castellucci, All Rights Reserved */
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h> /* for ntohl/htonl */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "hex.h"
#include "hash160.h"
#include "hsearchf.h"
#define HSEARCHF_DEBUG 0
#define HASHLEN RIPEMD160_DIGEST_LENGTH
#define RESULT(R) do { \
res = R; \
goto hsearchf_result; \
} while (0)
#define DO_MEMCMP(H) memcmp(H.uc, hash->uc, HASHLEN)
// use fadvise to do a readbehind
#define READ_AT(X, H) do { \
posix_fadvise(fileno(f), ((X*HASHLEN)&0xfffff000)-4096, 8192, POSIX_FADV_WILLNEED); \
if ((ret = fseek(f, X * HASHLEN, 0)) != 0) { return -1; } \
if ((ret = fread(H.uc, HASHLEN, 1, f)) != 1) { return -1; } \
++i; \
} while (0)
// interpolation search
int hsearchf(FILE *f, hash160_t *hash) {
int ret, res = 0, i = 0;
size_t file_sz;
struct stat sb;
hash160_t low_h, mid_h, high_h;
int64_t low_e, mid_e, high_e, entries;
int64_t vlow, vhigh, vtarget;
#if HSEARCHF_DEBUG > 0
unsigned char hexed[64];
#endif
if ((ret = fstat(fileno(f), &sb)) != 0) { return -1; }
file_sz = sb.st_size;
entries = file_sz / HASHLEN;
low_e = 0;
high_e = entries - 1;
vtarget = ntohl(hash->ul[0]);
memset(low_h.uc, 0x00, HASHLEN);
memset(high_h.uc, 0xff, HASHLEN);
// this tries to minimize reads, but does a few extra comparisons
while (low_e != high_e &&
memcmp(hash->uc, low_h.uc, HASHLEN) > 0 &&
memcmp(hash->uc, high_h.uc, HASHLEN) < 0) {
vlow = ntohl(low_h.ul[0]); vhigh = ntohl(high_h.ul[0]);
mid_e = low_e + (vtarget - vlow) * (high_e - low_e) / (vhigh - vlow);
READ_AT(mid_e, mid_h);
ret = DO_MEMCMP(mid_h);
#if HSEARCHF_DEBUG > 1
fprintf(stderr, "target %s checking %9jd %9jd %9jd",
hex(hash->uc, HASHLEN, hexed, sizeof(hexed)), low_e, mid_e, high_e);
fprintf(stderr, " got %s %11d %2d\n",
hex(mid_h.uc, HASHLEN, hexed, sizeof(hexed)), ret, i);
#endif
if (ret == 0) {
RESULT(1);
} else if (ret < 0) {
low_e = mid_e + 1;
READ_AT(low_e, low_h);
if (DO_MEMCMP(low_h) == 0) { RESULT(1); }
} else { // ret > 0
high_e = mid_e - 1;
READ_AT(high_e, high_h);
if (DO_MEMCMP(high_h) == 0) { RESULT(1); }
}
}
hsearchf_result:
#if HSEARCHF_DEBUG > 0
fprintf(stderr, "target: %s reads: %3d result: %d\n", hex(hash->uc, HASHLEN, hexed, sizeof(hexed)), i, res);
#endif
return res;
}
/* vim: set ts=2 sw=2 et ai si: */