You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1015 lines
35 KiB

/******************************************************************************
* Copyright © 2014-2015 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#include "iguana777.h"
#include <sys/stat.h>
#ifndef MAP_FILE
#define MAP_FILE 0
#endif
int32_t conv_date(int32_t *secondsp,char *buf);
uint32_t OS_conv_datenum(int32_t datenum,int32_t hour,int32_t minute,int32_t second) // datenum+H:M:S -> unix time
{
#ifdef __PNACL
PostMessage("timegm is not implemented\n");
return(0);
#else
struct tm t;
memset(&t,0,sizeof(t));
t.tm_year = (datenum / 10000) - 1900, t.tm_mon = ((datenum / 100) % 100) - 1, t.tm_mday = (datenum % 100);
t.tm_hour = hour, t.tm_min = minute, t.tm_sec = second;
return((uint32_t)timegm(&t));
#endif
}
int32_t OS_conv_unixtime(int32_t *secondsp,time_t timestamp) // gmtime -> datenum + number of seconds
{
struct tm t; int32_t datenum; uint32_t checktime; char buf[64];
t = *gmtime(&timestamp);
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ",&t); //printf("%s\n",buf);
datenum = conv_date(secondsp,buf);
if ( (checktime= OS_conv_datenum(datenum,*secondsp/3600,(*secondsp%3600)/60,*secondsp%60)) != timestamp )
{
printf("error: timestamp.%lu -> (%d + %d) -> %u\n",timestamp,datenum,*secondsp,checktime);
return(-1);
}
return(datenum);
}
char *OS_mvstr()
{
#ifdef __WIN32
return("rename");
#else
return("mv");
#endif
}
char *OS_rmstr() { return("rm"); }
int32_t os_supports_mappedfiles() { return(1); }
int32_t portable_truncate(char *fname,long filesize) { return(truncate(fname,filesize)); }
char *iguana_compatible_path(char *str)
{
return(str);
}
void ensure_directory(char *dirname)
{
FILE *fp; int32_t retval; char fname[512];
iguana_removefile(dirname,0);
sprintf(fname,"%s/.tmpmarker",dirname);
if ( (fp= fopen(iguana_compatible_path(fname),"rb")) == 0 )
{
if ( (fp= fopen(iguana_compatible_path(dirname),"rb")) == 0 )
{
retval = mkdir(dirname,511);
printf("mkdir.(%s) retval.%d errno.%d %s\n",dirname,retval,errno,strerror(errno));
} else fclose(fp), printf("dirname.(%s) exists\n",dirname);
if ( (fp= fopen(fname,"wb")) != 0 )
fclose(fp), printf("created.(%s)\n",fname);
else printf("cant create.(%s) errno.%d %s\n",fname,errno,strerror(errno));
} else fclose(fp), printf("%s exists\n",fname);
}
int32_t iguana_renamefile(char *fname,char *newfname)
{
char cmd[1024];
sprintf(cmd,"%s %s %s",OS_mvstr(),fname,newfname);
return(system(cmd));
}
int32_t iguana_removefile(char *fname,int32_t scrubflag)
{
FILE *fp;
char cmdstr[1024];
long i,fpos;
if ( (fp= fopen(iguana_compatible_path(fname),"rb+")) != 0 )
{
//printf("delete(%s)\n",fname);
if ( scrubflag != 0 )
{
fseek(fp,0,SEEK_END);
fpos = ftell(fp);
rewind(fp);
for (i=0; i<fpos; i++)
fputc(0xff,fp);
fflush(fp);
}
fclose(fp);
sprintf(cmdstr,"%s %s",OS_rmstr(),fname);
if ( system(iguana_compatible_path(cmdstr)) != 0 )
printf("error deleting file.(%s)\n",cmdstr);
else return(1);
}
return(0);
}
uint64_t iguana_filesize(char *fname)
{
FILE *fp; uint64_t fsize = 0;
if ( (fp= fopen(fname,"rb")) != 0 )
{
fseek(fp,0,SEEK_END);
fsize = ftell(fp);
fclose(fp);
}
return(fsize);
}
int32_t iguana_compare_files(char *fname,char *fname2)
{
int32_t offset,errs = 0;
long len,len2;
char buf[8192],buf2[8192];
FILE *fp,*fp2;
if ( (fp= fopen(iguana_compatible_path(fname),"rb")) != 0 )
{
if ( (fp2= fopen(iguana_compatible_path(fname2),"rb")) != 0 )
{
while ( (len= fread(buf,1,sizeof(buf),fp)) > 0 && (len2= fread(buf2,1,sizeof(buf2),fp2)) == len )
if ( (offset= memcmp(buf,buf2,len)) != 0 )
printf("compare error at offset.%d: (%s) src.%ld vs. (%s) dest.%ld\n",offset,fname,ftell(fp),fname2,ftell(fp2)), errs++;
fclose(fp2);
}
fclose(fp);
}
return(errs);
}
int64_t iguana_copyfile(char *src,char *dest,int32_t cmpflag)
{
int64_t allocsize,len = -1;
char *buf;
FILE *srcfp,*destfp;
if ( (srcfp= fopen(iguana_compatible_path(src),"rb")) != 0 )
{
if ( (destfp= fopen(iguana_compatible_path(dest),"wb")) != 0 )
{
allocsize = 1024 * 1024 * 128L;
buf = mycalloc('F',1,allocsize);
while ( (len= fread(buf,1,allocsize,srcfp)) > 0 )
if ( (long)fwrite(buf,1,len,destfp) != len )
printf("write error at (%s) src.%ld vs. (%s) dest.%ld\n",src,ftell(srcfp),dest,ftell(destfp));
len = ftell(destfp);
fclose(destfp);
myfree(buf,allocsize);
}
fclose(srcfp);
}
if ( len < 0 || (cmpflag != 0 && iguana_compare_files(src,dest) != 0) )
printf("Error copying files (%s) -> (%s)\n",src,dest), len = -1;
return(len);
}
void *map_file(char *fname,long *filesizep,int32_t enablewrite)
{
//void *mmap64(void *addr,size_t len,int32_t prot,int32_t flags,int32_t fildes,off_t off);
int32_t fd,rwflags,flags = MAP_FILE|MAP_SHARED;
uint64_t filesize;
void *ptr = 0;
*filesizep = 0;
if ( enablewrite != 0 )
fd = open(fname,O_RDWR);
else fd = open(fname,O_RDONLY);
if ( fd < 0 )
{
printf("map_file: error opening enablewrite.%d %s\n",enablewrite,fname);
return(0);
}
if ( *filesizep == 0 )
filesize = (uint64_t)lseek(fd,0,SEEK_END);
else filesize = *filesizep;
rwflags = PROT_READ;
if ( enablewrite != 0 )
rwflags |= PROT_WRITE;
//#if __i386__
ptr = mmap(0,filesize,rwflags,flags,fd,0);
//#else
//ptr = mmap64(0,filesize,rwflags,flags,fd,0);
//#endif
close(fd);
if ( ptr == 0 || ptr == MAP_FAILED )
{
printf("map_file.write%d: mapping %s failed? mp %p\n",enablewrite,fname,ptr);
return(0);
}
*filesizep = filesize;
return(ptr);
}
int32_t iguana_releasemap(void *ptr,uint64_t filesize)
{
int32_t retval;
if ( ptr == 0 )
{
printf("release_map_file: null ptr\n");
return(-1);
}
retval = munmap(ptr,filesize);
if ( retval != 0 )
printf("release_map_file: munmap error %p %llu: err %d\n",ptr,(long long)filesize,retval);
return(retval);
}
void _iguana_closemap(struct iguana_mappedptr *mp)
{
if ( mp->actually_allocated != 0 && mp->fileptr != 0 )
myaligned_free(mp->fileptr,mp->allocsize);
else if ( mp->fileptr != 0 )
iguana_releasemap(mp->fileptr,mp->allocsize);
mp->fileptr = 0;
mp->closetime = (uint32_t)time(NULL);
mp->opentime = 0;
}
void iguana_closemap(struct iguana_mappedptr *mp)
{
struct iguana_mappedptr tmp;
tmp = *mp;
_iguana_closemap(mp);
memset(mp,0,sizeof(*mp));
mp->actually_allocated = tmp.actually_allocated;
mp->allocsize = tmp.allocsize;
mp->rwflag = tmp.rwflag;
strcpy(mp->fname,tmp.fname);
}
int32_t iguana_syncmap(struct iguana_mappedptr *mp,long len)
{
//static long Sync_total;
int32_t err = -1;
if ( mp->actually_allocated != 0 )
return(0);
if ( mp->fileptr != 0 && mp->dirty != 0 )
{
if ( len == 0 )
len = mp->allocsize;
err = msync(mp->fileptr,len,MS_SYNC);
if ( err != 0 )
printf("sync (%s) len %llu, err %d errno.%d\n",mp->fname,(long long)len,err,errno);
//Sync_total += len;
mp->dirty = 0;
}
return(err);
}
long iguana_ensurefilesize(char *fname,long filesize,int32_t truncateflag)
{
FILE *fp;
char *zeroes;
long i,n,allocsize = 0;
//printf("ensure_filesize.(%s) %ld %s | ",fname,filesize,mbstr(filesize));
if ( (fp= fopen(iguana_compatible_path(fname),"rb")) != 0 )
{
fseek(fp,0,SEEK_END);
allocsize = ftell(fp);
fclose(fp);
//printf("(%s) exists size.%ld\n",fname,allocsize);
}
else
{
//printf("try to create.(%s)\n",fname);
if ( (fp= fopen(iguana_compatible_path(fname),"wb")) != 0 )
fclose(fp);
}
if ( allocsize < filesize )
{
//printf("filesize.%ld is less than %ld\n",filesize,allocsize);
if ( (fp= fopen(iguana_compatible_path(fname),"ab")) != 0 )
{
zeroes = myaligned_alloc(16L*1024*1024);
memset(zeroes,0,16*1024*1024);
n = filesize - allocsize;
while ( n > 16*1024*1024 )
{
fwrite(zeroes,1,16*1024*1024,fp);
n -= 16*1024*1024;
fprintf(stderr,"+");
}
for (i=0; i<n; i++)
fputc(0,fp);
fclose(fp);
myaligned_free(zeroes,16L*1024*1024);
}
return(filesize);
}
else if ( allocsize*truncateflag > filesize )
{
portable_truncate(fname,filesize);
return(filesize);
}
else return(allocsize);
}
int32_t iguana_openmap(struct iguana_mappedptr *mp)
{
uint64_t allocsize = mp->allocsize;
if ( mp->actually_allocated != 0 )
{
if ( mp->fileptr == 0 )
mp->fileptr = myaligned_alloc(mp->allocsize);
else memset(mp->fileptr,0,mp->allocsize);
return(0);
}
else
{
if ( mp->fileptr != 0 )
{
//printf("opening already open mappedptr, pending %p\n",mp->pending);
iguana_closemap(mp);
}
mp->allocsize = allocsize;
// printf("calling map_file with expected %ld\n",mp->allocsize);
mp->fileptr = map_file(mp->fname,&mp->allocsize,mp->rwflag);
if ( mp->fileptr == 0 || mp->allocsize != allocsize )
{
//printf("error mapping(%s) ptr %p mapped %ld vs allocsize %ld\n",mp->fname,mp->fileptr,mp->allocsize,allocsize);
return(-1);
}
mp->closetime = 0;
mp->opentime = (uint32_t)time(NULL);
}
return(0);
}
void *iguana_mappedptr(void **ptrp,struct iguana_mappedptr *mp,uint64_t allocsize,int32_t rwflag,char *fname)
{
uint64_t filesize;
mp->actually_allocated = !os_supports_mappedfiles();
if ( fname != 0 )
{
if ( strcmp(mp->fname,fname) == 0 )
{
if ( mp->fileptr != 0 )
{
iguana_releasemap(mp->fileptr,mp->allocsize);
mp->fileptr = 0;
}
iguana_openmap(mp);
if ( ptrp != 0 )
(*ptrp) = mp->fileptr;
return(mp->fileptr);
}
strcpy(mp->fname,fname);
}
else mp->actually_allocated = 1;
mp->rwflag = rwflag;
mp->allocsize = allocsize;
if ( rwflag != 0 && mp->actually_allocated == 0 && allocsize != 0 )
allocsize = iguana_ensurefilesize(fname,allocsize,0);
if ( iguana_openmap(mp) != 0 )
{
char str[65];
//printf("init_mappedptr %s.rwflag.%d | ",fname,rwflag);
if ( allocsize != 0 )
printf("error mapping(%s) rwflag.%d ptr %p mapped %llu vs allocsize %llu %s\n",fname,rwflag,mp->fileptr,(long long)mp->allocsize,(long long)allocsize,mbstr(str,allocsize));
else allocsize = mp->allocsize;
if ( rwflag != 0 && allocsize != mp->allocsize )
{
filesize = mp->allocsize;
if ( mp->fileptr != 0 )
iguana_releasemap(mp->fileptr,mp->allocsize);
mp->allocsize = allocsize;
mp->changedsize = (allocsize - filesize);
iguana_openmap(mp);
if ( mp->fileptr == 0 || mp->allocsize != allocsize )
{
printf("SECOND error mapping(%s) ptr %p mapped %llu vs allocsize %llu\n",fname,mp->fileptr,(long long)mp->allocsize,(long long)allocsize);
exit(-1);
}
}
}
if ( ptrp != 0 )
(*ptrp) = mp->fileptr;
return(mp->fileptr);
}
//int64_t iguana_packetsallocated(struct iguana_info *coin) { return(coin->R.packetsallocated - coin->R.packetsfreed); };
void *filealloc(struct iguana_mappedptr *M,char *fname,struct iguana_memspace *mem,long size)
{
//printf("mem->used %ld size.%ld | size.%ld\n",mem->used,size,mem->size);
//printf("filemalloc.(%s) new space.%ld %s\n",fname,mem->size,mbstr(size));
memset(M,0,sizeof(*M));
mem->totalsize = size;
if ( iguana_mappedptr(0,M,mem->totalsize,1,fname) == 0 )
{
printf("couldnt create mapped file.(%s)\n",fname);
exit(-1);
}
mem->ptr = M->fileptr;
mem->used = 0;
return(M->fileptr);
}
void *iguana_tmpalloc(struct iguana_info *coin,char *name,struct iguana_memspace *mem,long origsize)
{
char fname[1024]; void *ptr; long size;
#ifdef __PNACL
return(mycalloc('T',1,origsize));
#endif
//portable_mutex_lock(&mem->mutex);
if ( origsize != 0 && (mem->M.fileptr == 0 || (mem->used + origsize) > mem->totalsize) )
{
coin->TMPallocated += origsize;
memset(&mem->M,0,sizeof(mem->M));
sprintf(fname,"tmp/%s/%s.%d",coin->symbol,name,mem->counter), iguana_compatible_path(fname);
mem->counter++;
if ( mem->totalsize == 0 )
{
//if ( strcmp(name,"recv") == 0 )
// mem->size = IGUANA_RSPACE_SIZE * ((strcmp(coin->symbol,"BTC") == 0) ? 16 : 1);
// else
#ifdef IGUANA_MAPHASHTABLES
mem->totalsize = (1024 * 1024 * 128);
#else
mem->size = (1024 * 1024 * 16);
#endif
}
//if ( coin->R.RSPACE.size == 0 )
// coin->R.RSPACE.size = mem->size;
if ( mem->totalsize > origsize )
size = mem->totalsize;
else size = origsize;
fprintf(stderr,"filealloc.(%s) -> ",fname);
if ( filealloc(&mem->M,fname,mem,size) == 0 )
{
printf("couldnt map tmpfile %s\n",fname);
return(0);
}
fprintf(stderr,"created\n");
}
ptr = iguana_memalloc(mem,origsize,1);
//portable_mutex_unlock(&mem->mutex);
return(ptr);
}
#ifdef oldway
void *iguana_kvfixiterator(struct iguana_info *coin,struct iguanakv *kv,struct iguana_kvitem *item,uint64_t args,void *key,void *value,int32_t valuesize)
{
int64_t offset = (int64_t)args;
if ( args != 0 && (kv->flags & IGUANA_ITEMIND_DATA) != 0 )
{
item->hh.key = (void *)((uint64_t)item->hh.key + (int64_t)offset);
//printf("iguana_kvfixiterator rawind.%-5d: (%s)\n",item->rawind,bits256_str(*(bits256 *)item->hh.key));
}
return(0);
}
void *_iguana_kvensure(struct iguana_info *coin,int32_t rwflag,int32_t *maxindp,char *name,char *fname,double mult,int32_t incr,uint32_t ind,struct iguana_mappedptr *M,int32_t HDDvaluesize)
{
long needed,prevsize = 0;
needed = (ind + 2) * HDDvaluesize;
//printf("ensure.%s ind.%d needed.%ld origptr.%p\n",kv->name,ind,needed,origptr);
if ( needed > M->allocsize )
{
needed = (((needed * mult) + incr * HDDvaluesize) / HDDvaluesize) * HDDvaluesize;
printf("REMAP.%s %llu -> %ld [%ld] (%s) (ind.%d mult.%f incr.%d size.%d\n",name,(long long)M->allocsize,needed,(long)(needed - M->allocsize)/HDDvaluesize,fname,ind,mult,incr,HDDvaluesize);
if ( M->fileptr != 0 )
{
iguana_syncmap(M,0);
iguana_releasemap(M->fileptr,M->allocsize);
M->fileptr = 0, prevsize = M->allocsize;
M->allocsize = 0;
}
needed = iguana_ensurefilesize(fname,needed,0);
}
if ( M->fileptr == 0 )
{
if ( iguana_mappedptr(0,M,0,rwflag,fname) != 0 )
{
if ( 1 && prevsize > M->allocsize )
memset((void *)((uint64_t)M->fileptr + prevsize),0,(M->allocsize - prevsize));
printf("%p %s maxitems.%llu (MEMsize.%ld / itemsize.%d) prevsize.%ld needed.%ld\n",M->fileptr,name,(long long)*maxindp,(long)M->allocsize,HDDvaluesize,prevsize,needed);
}
}
return(M->fileptr);
}
void *iguana_kvensure(struct iguana_info *coin,struct iguanakv *kv,uint32_t ind)
{
char fname[512]; void *origptr; int32_t maxitemind,n,rwflag = 1;
if ( (int32_t)ind < 0 )
ind = 0;
origptr = kv->HDDitems;
kv->HDDitems = _iguana_kvensure(coin,rwflag,&kv->maxitemind,kv->name,kv->fname,kv->mult,kv->incr,ind,&kv->M,kv->HDDvaluesize);
if ( kv->HDDitemsp != 0 )
*kv->HDDitemsp = kv->HDDitems;
n = (int32_t)(kv->M.allocsize / kv->HDDvaluesize);
if ( ind < n )
ind = n;
if ( kv->valuesize3 != 0 )
{
sprintf(fname,"%s3",kv->fname);
if ( (kv->HDDitems3= _iguana_kvensure(coin,rwflag,&maxitemind,kv->name,fname,kv->mult,kv->incr,ind,&kv->M3,kv->valuesize3)) == 0 )
{
printf("HDDitems3 null ptr for %s\n",fname);
return(0);
}
//printf("third file\n");
if ( kv->HDDitems3p != 0 )
*kv->HDDitems3p = kv->HDDitems3;
}
if ( kv->valuesize2 != 0 )
{
sprintf(fname,"%s2",kv->fname);
if ( (kv->HDDitems2= _iguana_kvensure(coin,rwflag,&maxitemind,kv->name,fname,kv->mult,kv->incr,ind,&kv->M2,kv->valuesize2)) == 0 )
{
printf("HDDitems3 null ptr for %s\n",fname);
return(0);
}
//printf("second file\n");
if ( kv->HDDitems2p != 0 )
*kv->HDDitems2p = kv->HDDitems2;
}
if ( origptr != 0 && origptr != kv->M.fileptr && (kv->flags & IGUANA_ITEMIND_DATA) != 0 )
{
if ( iguana_kviterate(coin,kv,(int64_t)((int64_t)kv->HDDitems - (int64_t)origptr),iguana_kvfixiterator) != 0 )
printf("ERROR relinked pointers\n");
else printf("hashtable relinked\n");
kv->incr *= 1.25;
}
return(kv->HDDitems);
}
void *iguana_kvsaveiterator(struct iguana_info *coin,struct iguanakv *kv,struct iguana_kvitem *item,uint64_t args,void *key,void *value,int32_t valuesize)
{
FILE *fp = (FILE *)args;
if ( args != 0 )
{
if ( fwrite(value,1,kv->RAMvaluesize,fp) != kv->RAMvaluesize )
{
printf("Error saving key.[%d]\n",kv->RAMvaluesize);
return(value);
}
}
return(0);
}
long iguana_kvsave(struct iguana_info *coin,struct iguanakv *kv)
{
FILE *fp; long retval = -1; char fname[512],oldfname[512],cmd[512];
sprintf(fname,"%s.tmp",kv->name);
if ( (fp= fopen(fname,"wb")) != 0 )
{
if ( iguana_kviterate(coin,kv,(uint64_t)fp,iguana_kvsaveiterator) == 0 )
{
printf("save %ld to HDD\n",ftell(fp));
retval = ftell(fp);
}
else printf("error saving item at %ld\n",ftell(fp));
fclose(fp);
} else printf("error creating(%s)\n",fname);
if ( retval > 0 )
{
sprintf(oldfname,"%s.%u",kv->name,(uint32_t)time(NULL));
sprintf(cmd,"%s %s %s",OS_mvstr(),kv->name,oldfname);
retval = system(cmd);
sprintf(cmd,"%s %s %s",OS_mvstr(),fname,kv->name);
retval = system(cmd);
}
return(retval);
}
int32_t iguana_valuesize(struct iguana_info *coin,struct iguanakv *kv)
{
int32_t valuesize = kv->RAMvaluesize;
return(valuesize);
}
int32_t iguana_itemsize(struct iguana_info *coin,struct iguanakv *kv)
{
int32_t itemsize = sizeof(struct iguana_kvitem);
if ( (kv->flags & IGUANA_ITEMIND_DATA) == 0 )
itemsize += iguana_valuesize(coin,kv);
return(itemsize);
}
void *iguana_itemvalue(struct iguana_info *coin,void **itemkeyp,struct iguanakv *kv,void *ptr,struct iguana_kvitem *item)
{
void *itemvalue = 0;
*itemkeyp = 0;
if ( (kv->flags & IGUANA_ITEMIND_DATA) != 0 )
{
if ( ptr != 0 )
{
*itemkeyp = &((uint8_t *)ptr)[kv->keyoffset];
itemvalue = ptr;
} else printf("error setting itemvalue\n");
}
if ( *itemkeyp == 0 )
{
*itemkeyp = item->keyvalue;
itemvalue = &item->keyvalue[kv->keysize];
}
return(itemvalue);
}
void *iguana_itemptr(struct iguana_info *coin,struct iguanakv *kv,uint32_t itemind)
{
void *ptr = kv->HDDitems;
//printf("%s itemind.%d\n",kv->name,itemind);
if ( ptr == 0 || itemind >= kv->maxitemind )
{
kv->HDDitems = iguana_kvensure(coin,kv,itemind+1);
if ( (ptr= kv->HDDitems) == 0 )
{
printf("SECOND ERROR %s overflow? %p itemind.%llu vs max.%llu\n",kv->name,ptr,(long long)itemind,(long long)kv->maxitemind);
return(0);
}
}
ptr = (void *)((uint64_t)ptr + kv->HDDvaluesize*itemind);
return(ptr);
}
void iguana_copy(struct iguana_info *coin,struct iguanakv *kv,int32_t rwflag,void *itemvalue,void *value,int32_t valuesize)
{
void *src,*dest;
/*if ( (kv->flags & IGUANA_MAPPED_ITEM) != 0 && rwflag != 0 )
{
itemvalue = (void *)(((uint64_t))itemvalue + sizeof(UT_hash_handle));
value = (void *)(((uint64_t))value + sizeof(UT_hash_handle));
valuesize -= sizeof(UT_hash_handle);
//printf("value.%p itemvalue.%p valuesize.%d\n",value,itemvalue,valuesize);
}*/
if ( rwflag != 0 )
src = value, dest = itemvalue;
else src = itemvalue, dest = value;
memcpy(dest,src,valuesize);
}
static int32_t iguana_RWmmap(int32_t writeflag,void *value,struct iguana_info *coin,struct iguanakv *kv,uint32_t itemind)
{
static const uint8_t zeroes[4096];
void *ptr,*itemvalue=0; int32_t i,itemsize,valuesize,retval = 0;
itemsize = iguana_itemsize(coin,kv);
valuesize = iguana_valuesize(coin,kv);
if ( (ptr= iguana_itemptr(coin,kv,itemind)) != 0 )
{
//itemvalue = iguana_itemvalue(coin,&itemkey,kv,ptr,0);
if ( writeflag != 0 )
{
//struct iguana777_addrinfo *A; struct coin_offsets B,tmpB;
//itemsize = kv->RAMvaluesize;
/*if ( strcmp(sp->name,"addrinfos") == 0 )
{
A = ptr;
itemsize = (sizeof(*A) - sizeof(A->coinaddr) + A->addrlen + A->scriptlen);
}*/
if ( writeflag == 1 && (kv->flags & IGUANA_VOLATILE) == 0 )
{
/*if ( strcmp(sp->name,"blocks") == 0 )
{
memcpy(&B,ptr,sizeof(B));
memcpy(&tmpB,value,sizeof(tmpB));
if ( memcmp(&B.blockhash.bytes,zeroes,sizeof(B.blockhash)) == 0 && memcmp(&B.merkleroot.bytes,zeroes,sizeof(B.merkleroot)) == 0 )
B.blockhash = tmpB.blockhash, B.merkleroot = tmpB.merkleroot, ptr = &B;
}*/
if ( 0 && memcmp(value,itemvalue,valuesize) != 0 && valuesize <= sizeof(zeroes) )
{
if ( memcmp(itemvalue,zeroes,valuesize) != 0 )
{
printf("\n");
for (i=0; i<valuesize; i++)
printf("%02x ",((uint8_t *)itemvalue)[i]);
printf("existing.%s %d <-- overwritten\n",kv->name,kv->RAMvaluesize);
for (i=0; i<valuesize; i++)
printf("%02x ",((uint8_t *)value)[i]);
printf("new value.%s %d itemind.%u fileptr.%p ptr.%p\n",kv->name,kv->RAMvaluesize,itemind,kv->M.fileptr,ptr);
}
}
}
if ( kv->fp == 0 )
iguana_copy(coin,kv,writeflag,ptr,value,valuesize);
else // all ready for rb+ fp and readonly mapping, but need to init properly
{
/*fseek(sp->fp,(uint64_t)sp->itemsize * itemind,SEEK_SET);
fwrite(value,1,valuesize,sp->fp);
if ( memcmp(itemvalue,value,valuesize) != 0 )
printf("FATAL: write mmap error\n"), getchar();*/
printf("iguana_RWmmap: need to test sp->fp first\n"), exit(1);
}
}
else iguana_copy(coin,kv,writeflag,ptr,value,valuesize);
} else retval = -2;
return(retval);
}
void iguana_kvlock(struct iguana_info *coin,struct iguanakv *kv)
{
if ( kv->threadsafe != 0 )
portable_mutex_lock(&kv->KVmutex);
}
void iguana_kvunlock(struct iguana_info *coin,struct iguanakv *kv)
{
if ( kv->threadsafe != 0 )
portable_mutex_unlock(&kv->KVmutex);
}
int32_t iguana_kvdelete(struct iguana_info *coin,struct iguanakv *kv,void *key)
{
int32_t retval = -1; struct iguana_kvitem *ptr = 0;
if ( kv == 0 )
return(-1);
iguana_kvlock(coin,kv);
HASH_FIND(hh,kv->hashtables[((uint8_t *)key)[kv->keysize>>1]],key,kv->keysize,ptr);
if ( ptr != 0 )
{
HASH_DELETE(hh,kv->hashtables[((uint8_t *)key)[kv->keysize>>1]],ptr);
if ( (kv->flags & IGUANA_MAPPED_ITEM) == 0 )
myfree(ptr,iguana_itemsize(coin,kv));
retval = 0;
}
iguana_kvlock(coin,kv);
return(retval);
}
void *_iguana_kvread(struct iguana_info *coin,struct iguanakv *kv,void *key,void *value,uint32_t *itemindp)
{
void *itemkey,*itemvalue,*ptr=0; int32_t valuesize,itemind = 0; struct iguana_kvitem *item = 0;
if ( kv == 0 )
{
printf("iguana_kvread: null ramkv??\n");
return(0);
}
if ( kv->keysize == 0 )
{
printf("kvwrite %s only supports itemind MMap access\n",kv->name);
return(0);
}
valuesize = iguana_valuesize(coin,kv);
//printf("search for [%llx] keysize.%d\n",*(long long *)key,kv->keysize);
HASH_FIND(hh,kv->hashtables[((uint8_t *)key)[kv->keysize>>1]],key,kv->keysize,item);
if ( item != 0 )
{
if ( itemindp != 0 )
*itemindp = itemind = item->hh.itemind;
if ( (kv->flags & IGUANA_ITEMIND_DATA) != 0 )
ptr = iguana_itemptr(coin,kv,itemind);
if ( (itemvalue= iguana_itemvalue(coin,&itemkey,kv,ptr,item)) != 0 )
{
//printf("itemind.%d: key.%p value.%p valuesize.%d\n",itemind,itemkey,itemvalue,valuesize);
iguana_copy(coin,kv,0,itemvalue,value,valuesize);
}
else printf("_kvread null itemvalue for itemind.%d\n",itemind);
return(value);
}
//printf("cache miss %s\n",bits256_str(*(bits256 *)key));
if ( itemindp != 0 )
*itemindp = 0;
return(0);
}
void *_iguana_kvwrite(struct iguana_info *coin,struct iguanakv *kv,void *key,void *value,uint32_t *itemindp)
{
void *ptr=0,*itemvalue=0,*itemkey=0; struct iguana_kvitem *item = 0; uint32_t itemsize,valuesize,itemind = *itemindp;
if ( kv == 0 )
return(0);
valuesize = iguana_valuesize(coin,kv);
itemsize = iguana_itemsize(coin,kv);
if ( kv->keysize == 0 )
{
printf("kvwrite %s only supports itemind MMap access\n",kv->name);
return(0);
}
HASH_FIND(hh,kv->hashtables[((uint8_t *)key)[kv->keysize>>1]],key,kv->keysize,item);
if ( item != 0 )
{
if ( 0 && itemind != item->hh.itemind && itemind != (uint32_t)-1 )
{
printf("%s override itemind %d -> %d\n",kv->name,item->hh.itemind,itemind);
item->hh.itemind = itemind;
} else itemind = item->hh.itemind;
*itemindp = itemind;
if ( (kv->flags & IGUANA_ITEMIND_DATA) != 0 )
ptr = iguana_itemptr(coin,kv,itemind);
if ( (itemvalue= iguana_itemvalue(coin,&itemkey,kv,ptr,item)) != 0 )
{
if ( memcmp(itemvalue,value,valuesize) != 0 )
{
//printf("%s: item.%d updating %p\n",kv->name,item->hh.itemind,key);
iguana_copy(coin,kv,1,itemvalue,value,valuesize);
kv->updated++;
}
} else printf("kvwrite null itemvalue itemind.%d\n",itemind);
return(item);
}
else
{
kv->numkeys++;
if ( itemind == (uint32_t)-1 )
itemind = kv->numkeys;
*itemindp = itemind;
if ( item == 0 )
{
if ( (kv->flags & IGUANA_ITEMIND_DATA) != 0 )
ptr = iguana_itemptr(coin,kv,itemind);
item = ((kv->flags & IGUANA_MAPPED_ITEM) == 0) ? mycalloc('I',1,itemsize) : iguana_tmpalloc(coin,kv->name,&kv->HASHPTRS,itemsize);
if ( item == 0 )
printf("fatal out of mem error\n"), getchar();
}
itemvalue = iguana_itemvalue(coin,&itemkey,kv,ptr,item);
}
if ( itemvalue != 0 && itemkey != 0 && item != 0 )
{
valuesize = iguana_valuesize(coin,kv);
item->hh.itemind = itemind;
iguana_copy(coin,kv,1,itemvalue,value,valuesize);
memcpy(itemkey,key,kv->keysize);
//if ( strcmp(kv->name,"txids") == 0 )
//printf("add.(%s) itemind.%d kv->numkeys.%d keysize.%d (%s) valuesize.%d:%d\n",kv->name,itemind,kv->numkeys,kv->keysize,bits256_str(*(bits256 *)key),kv->HDDvaluesize,kv->RAMvaluesize);
HASH_ADD_KEYPTR(hh,kv->hashtables[((uint8_t *)itemkey)[kv->keysize>>1]],itemkey,kv->keysize,item);
kv->M.dirty++;
HASH_FIND(hh,kv->hashtables[((uint8_t *)key)[kv->keysize>>1]],key,kv->keysize,item);
if ( kv->dispflag != 0 || item == 0 || item->hh.itemind != itemind )
fprintf(stderr,">> %s found item.%p iguana_kvwrite numkeys.%d kv.(%p) table.%p write kep.%p size.%d, %p value.(%08x) size.%d itemind.%d:%d\n",kv->name,item,kv->numkeys,key,kv->hashtables[((uint8_t *)itemkey)[kv->keysize>>1]],itemkey,kv->keysize,itemvalue,itemvalue!=0?calc_crc32(0,itemvalue,valuesize):0,valuesize,item!=0?item->hh.itemind:0,itemind);
if ( item != 0 )
return(value);
else printf("null item after find kvwrite error\n"), getchar();
} else printf("kvwrite pointer error %p %p %p\n",itemkey,itemvalue,item), getchar();
return(0);
}
void *iguana_kvread(struct iguana_info *coin,struct iguanakv *kv,void *key,void *value,uint32_t *itemindp)
{
void *retptr = 0;
// if ( strcmp(kv->name,"txids") == 0 )
// printf("iguana_kvread.(%s) key.%p keysize.%d flag.%d itemind.%d\n",kv->name,key,kv->keysize,kv->flags,*itemindp);
portable_mutex_lock(&kv->MMmutex);
if ( key == 0 || kv->keysize == 0 )
{
if ( iguana_RWmmap(0,value,coin,kv,*itemindp) == 0 )
retptr = value;
else printf("%s %d vs %d RMmmap.0 error\n",kv->name,*itemindp,(int32_t)(kv->M.allocsize/kv->HDDvaluesize));
} else retptr = _iguana_kvread(coin,kv,key,value,itemindp);
portable_mutex_unlock(&kv->MMmutex);
return(retptr);
}
void *iguana_kvwrite(struct iguana_info *coin,struct iguanakv *kv,void *key,void *value,uint32_t *itemindp)
{
void *retptr = 0;
portable_mutex_lock(&kv->MMmutex);
if ( key == 0 || kv->keysize == 0 )
{
kv->M.dirty++;
if ( iguana_RWmmap(1,value,coin,kv,*itemindp) == 0 )
retptr = value;
else printf("%s %d vs %d RMmmap.1 error\n",kv->name,*itemindp,(int32_t)(kv->M.allocsize/kv->HDDvaluesize));
} else retptr = _iguana_kvwrite(coin,kv,key,value,itemindp);
portable_mutex_unlock(&kv->MMmutex);
return(retptr);
}
int32_t iguana_kvchecktable(struct iguana_info *coin,struct iguanakv *kv)
{
uint32_t itemind,checkind; int32_t err = 0; uint8_t key[8192];
for (itemind=1; itemind<=kv->numkeys; itemind++)
{
if ( iguana_RWmmap(0,kv->space,coin,kv,itemind) == 0 )
{
if ( kv->keysize != 0 && kv->keysize < sizeof(key) )
{
memcpy(key,(void *)((long)kv->space + kv->keyoffset),kv->keysize);
if ( _iguana_kvread(coin,kv,key,kv->space,&checkind) == 0 || checkind != itemind )
{
printf("kvread.%s miscompares checkind.%d vs %d\n",kv->name,checkind,itemind);
err++;
}
}
} else err++, printf("%s itemind.%d doesnt map properly\n",kv->name,itemind);
}
return(-err);
}
void *iguana_kviterate(struct iguana_info *coin,struct iguanakv *kv,uint64_t args,void *(*iterator)(struct iguana_info *coin,struct iguanakv *kv,struct iguana_kvitem *item,uint64_t args,void *key,void *value,int32_t valuesize))
{
struct iguana_kvitem *item,*tmp; int32_t t; void *ptr=0,*itemvalue,*itemkey=0,*retval = 0;
if ( kv == 0 )
return(0);
for (t=0; t<0x100; t++)
{
HASH_ITER(hh,kv->hashtables[t],item,tmp)
{
if ( (kv->flags & IGUANA_ITEMIND_DATA) != 0 )
ptr = iguana_itemptr(coin,kv,item->hh.itemind);
if ( (itemvalue= iguana_itemvalue(coin,&itemkey,kv,ptr,item)) != 0 && itemkey != 0 )
{
if ( (retval= (*iterator)(coin,kv,item,args,itemkey,itemvalue,kv->RAMvaluesize)) != 0 )
return(retval);
} else return(retval);
}
}
return(0);
}
int32_t iguana_kvtruncate(struct iguana_info *coin,struct iguanakv *kv,uint32_t maxitemind)
{
struct iguana_kvitem *item,*tmp; int32_t t,n = 0;
if ( kv->numkeys < maxitemind )
return(-1);
for (t=0; t<0x100; t++)
{
HASH_ITER(hh,kv->hashtables[t],item,tmp)
{
if ( item->hh.itemind >= maxitemind )
{
HASH_DEL(kv->hashtables[t],item);
if ( (kv->flags & IGUANA_MAPPED_ITEM) == 0 )
myfree(item,iguana_itemsize(coin,kv));
n++;
}
}
}
printf(">>>>>>>>>> kv.%s truncated.%d to maxitemind.%d\n",kv->name,n,maxitemind);
kv->numkeys = maxitemind;
return(iguana_kvchecktable(coin,kv));
}
void iguana_kvfree(struct iguana_info *coin,struct iguanakv *kv)
{
struct iguana_kvitem *ptr,*tmp; int32_t t;
if ( kv != 0 )
{
iguana_kvlock(coin,kv);
for (t=0; t<0x100; t++)
{
HASH_ITER(hh,kv->hashtables[t],ptr,tmp)
{
HASH_DEL(kv->hashtables[t],ptr);
if ( (kv->flags & IGUANA_MAPPED_ITEM) == 0 )
myfree(ptr,iguana_itemsize(coin,kv));
}
}
iguana_kvunlock(coin,kv);
myfree(kv,sizeof(*kv));
}
}
int32_t iguana_kvclone(struct iguana_info *coin,struct iguanakv *clone,struct iguanakv *kv)
{
void *ptr=0,*itemkey,*itemvalue; struct iguana_kvitem *item,*tmp; int32_t t,n = 0;
printf("need to add support for mapped data\n");
if ( kv != 0 )
{
for (t=0; t<0x100; t++)
{
HASH_ITER(hh,kv->hashtables[t],item,tmp)
{
if ( (kv->flags & IGUANA_ITEMIND_DATA) != 0 )
ptr = iguana_itemptr(coin,kv,item->hh.itemind);
if ( (itemvalue= iguana_itemvalue(coin,&itemkey,kv,ptr,item)) != 0 && itemkey != 0 )
{
iguana_kvwrite(coin,clone,itemkey,itemvalue,&item->hh.itemind);
n++;
}
}
}
}
return(n);
}
int32_t iguana_kvdisp(struct iguana_info *coin,struct iguanakv *kv)
{
struct iguana_kvitem *item,*tmp; void *ptr=0,*itemkey,*itemvalue; int32_t t,n = 0; char hexstr[8192];
printf("iguana_kvdisp.(%s) numkeys.%d\n",kv->name,kv->numkeys);
if ( kv == 0 )
return(0);
for (t=0; t<0x100; t++)
{
HASH_ITER(hh,kv->hashtables[t],item,tmp)
{
if ( (kv->flags & IGUANA_ITEMIND_DATA) != 0 )
ptr = iguana_itemptr(coin,kv,item->hh.itemind);
if ( (itemvalue= iguana_itemvalue(coin,&itemkey,kv,ptr,item)) != 0 )
{
init_hexbytes_noT(hexstr,itemvalue,kv->RAMvaluesize);
char str[65];
bits256_str(str,*(bits256 *)itemkey);
printf("itemind.%d %s %s len.%d height.%d\n",item->hh.itemind,str,hexstr,kv->RAMvaluesize,((struct iguana_block *)itemvalue)->height);
}
n++;
}
}
printf("iguana_kvdisp.(%s) n.%d items\n",kv->name,n);
return(n);
}
#endif