/****************************************************************************** * 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 #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(×tamp); 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 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 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; iname,kv->RAMvaluesize); for (i=0; iname,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