Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
bitvec.c496 linesDownload Raw Back to src
1/*2** 2008 February 163**4** The author disclaims copyright to this source code.  In place of5** a legal notice, here is a blessing:6**7**    May you do good and not evil.8**    May you find forgiveness for yourself and forgive others.9**    May you share freely, never taking more than you give.10**11*************************************************************************12** This file implements an object that represents a fixed-length13** bitmap.  Bits are numbered starting with 1.14**15** A bitmap is used to record which pages of a database file have been16** journalled during a transaction, or which pages have the "dont-write"17** property.  Usually only a few pages are meet either condition.18** So the bitmap is usually sparse and has low cardinality.19** But sometimes (for example when during a DROP of a large table) most20** or all of the pages in a database can get journalled.  In those cases,21** the bitmap becomes dense with high cardinality.  The algorithm needs22** to handle both cases well.23**24** The size of the bitmap is fixed when the object is created.25**26** All bits are clear when the bitmap is created.  Individual bits27** may be set or cleared one at a time.28**29** Test operations are about 100 times more common that set operations.30** Clear operations are exceedingly rare.  There are usually between31** 5 and 500 set operations per Bitvec object, though the number of sets can32** sometimes grow into tens of thousands or larger.  The size of the33** Bitvec object is the number of pages in the database file at the34** start of a transaction, and is thus usually less than a few thousand,35** but can be as large as 2 billion for a really big database.36*/37#include "sqliteInt.h"38 39/* Size of the Bitvec structure in bytes. */40#define BITVEC_SZ        51241 42/* Round the union size down to the nearest pointer boundary, since that's how43** it will be aligned within the Bitvec struct. */44#define BITVEC_USIZE \45    (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))46 47/* Type of the array "element" for the bitmap representation.48** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE.49** Setting this to the "natural word" size of your CPU may improve50** performance. */51#define BITVEC_TELEM     u852/* Size, in bits, of the bitmap element. */53#define BITVEC_SZELEM    854/* Number of elements in a bitmap array. */55#define BITVEC_NELEM     (BITVEC_USIZE/sizeof(BITVEC_TELEM))56/* Number of bits in the bitmap array. */57#define BITVEC_NBIT      (BITVEC_NELEM*BITVEC_SZELEM)58 59/* Number of u32 values in hash table. */60#define BITVEC_NINT      (BITVEC_USIZE/sizeof(u32))61/* Maximum number of entries in hash table before62** sub-dividing and re-hashing. */63#define BITVEC_MXHASH    (BITVEC_NINT/2)64/* Hashing function for the aHash representation.65** Empirical testing showed that the *37 multiplier66** (an arbitrary prime)in the hash function provided67** no fewer collisions than the no-op *1. */68#define BITVEC_HASH(X)   (((X)*1)%BITVEC_NINT)69 70#define BITVEC_NPTR      ((u32)(BITVEC_USIZE/sizeof(Bitvec *)))71 72 73/*74** A bitmap is an instance of the following structure.75**76** This bitmap records the existence of zero or more bits77** with values between 1 and iSize, inclusive.78**79** There are three possible representations of the bitmap.80** If iSize<=BITVEC_NBIT, then Bitvec.u.aBitmap[] is a straight81** bitmap.  The least significant bit is bit 1.82**83** If iSize>BITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is84** a hash table that will hold up to BITVEC_MXHASH distinct values.85**86** Otherwise, the value i is redirected into one of BITVEC_NPTR87** sub-bitmaps pointed to by Bitvec.u.apSub[].  Each subbitmap88** handles up to iDivisor separate values of i.  apSub[0] holds89** values between 1 and iDivisor.  apSub[1] holds values between90** iDivisor+1 and 2*iDivisor.  apSub[N] holds values between91** N*iDivisor+1 and (N+1)*iDivisor.  Each subbitmap is normalized92** to hold deal with values between 1 and iDivisor.93*/94struct Bitvec {95  u32 iSize;      /* Maximum bit index.  Max iSize is 4,294,967,296. */96  u32 nSet;       /* Number of bits that are set - only valid for aHash97                  ** element.  Max is BITVEC_NINT.  For BITVEC_SZ of 512,98                  ** this would be 125. */99  u32 iDivisor;   /* Number of bits handled by each apSub[] entry. */100                  /* Should >=0 for apSub element. */101                  /* Max iDivisor is max(u32) / BITVEC_NPTR + 1.  */102                  /* For a BITVEC_SZ of 512, this would be 34,359,739. */103  union {104    BITVEC_TELEM aBitmap[BITVEC_NELEM];    /* Bitmap representation */105    u32 aHash[BITVEC_NINT];      /* Hash table representation */106    Bitvec *apSub[BITVEC_NPTR];  /* Recursive representation */107  } u;108};109 110 111/*112** Create a new bitmap object able to handle bits between 0 and iSize,113** inclusive.  Return a pointer to the new object.  Return NULL if114** malloc fails.115*/116Bitvec *sqlite3BitvecCreate(u32 iSize){117  Bitvec *p;118  assert( sizeof(*p)==BITVEC_SZ );119  p = sqlite3MallocZero( sizeof(*p) );120  if( p ){121    p->iSize = iSize;122  }123  return p;124}125 126/*127** Check to see if the i-th bit is set.  Return true or false.128** If p is NULL (if the bitmap has not been created) or if129** i is out of range, then return false.130*/131int sqlite3BitvecTestNotNull(Bitvec *p, u32 i){132  assert( p!=0 );133  i--;134  if( i>=p->iSize ) return 0;135  while( p->iDivisor ){136    u32 bin = i/p->iDivisor;137    i = i%p->iDivisor;138    p = p->u.apSub[bin];139    if (!p) {140      return 0;141    }142  }143  if( p->iSize<=BITVEC_NBIT ){144    return (p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))))!=0;145  } else{146    u32 h = BITVEC_HASH(i++);147    while( p->u.aHash[h] ){148      if( p->u.aHash[h]==i ) return 1;149      h = (h+1) % BITVEC_NINT;150    }151    return 0;152  }153}154int sqlite3BitvecTest(Bitvec *p, u32 i){155  return p!=0 && sqlite3BitvecTestNotNull(p,i);156}157 158/*159** Set the i-th bit.  Return 0 on success and an error code if160** anything goes wrong.161**162** This routine might cause sub-bitmaps to be allocated.  Failing163** to get the memory needed to hold the sub-bitmap is the only164** that can go wrong with an insert, assuming p and i are valid.165**166** The calling function must ensure that p is a valid Bitvec object167** and that the value for "i" is within range of the Bitvec object.168** Otherwise the behavior is undefined.169*/170int sqlite3BitvecSet(Bitvec *p, u32 i){171  u32 h;172  if( p==0 ) return SQLITE_OK;173  assert( i>0 );174  assert( i<=p->iSize );175  i--;176  while((p->iSize > BITVEC_NBIT) && p->iDivisor) {177    u32 bin = i/p->iDivisor;178    i = i%p->iDivisor;179    if( p->u.apSub[bin]==0 ){180      p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );181      if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM_BKPT;182    }183    p = p->u.apSub[bin];184  }185  if( p->iSize<=BITVEC_NBIT ){186    p->u.aBitmap[i/BITVEC_SZELEM] |= 1 << (i&(BITVEC_SZELEM-1));187    return SQLITE_OK;188  }189  h = BITVEC_HASH(i++);190  /* if there wasn't a hash collision, and this doesn't */191  /* completely fill the hash, then just add it without */192  /* worrying about sub-dividing and re-hashing. */193  if( !p->u.aHash[h] ){194    if (p->nSet<(BITVEC_NINT-1)) {195      goto bitvec_set_end;196    } else {197      goto bitvec_set_rehash;198    }199  }200  /* there was a collision, check to see if it's already */201  /* in hash, if not, try to find a spot for it */202  do {203    if( p->u.aHash[h]==i ) return SQLITE_OK;204    h++;205    if( h>=BITVEC_NINT ) h = 0;206  } while( p->u.aHash[h] );207  /* we didn't find it in the hash.  h points to the first */208  /* available free spot. check to see if this is going to */209  /* make our hash too "full".  */210bitvec_set_rehash:211  if( p->nSet>=BITVEC_MXHASH ){212    unsigned int j;213    int rc;214    u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash));215    if( aiValues==0 ){216      return SQLITE_NOMEM_BKPT;217    }else{218      memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));219      memset(p->u.apSub, 0, sizeof(p->u.apSub));220      p->iDivisor = p->iSize/BITVEC_NPTR;221      if( (p->iSize%BITVEC_NPTR)!=0 ) p->iDivisor++;222      if( p->iDivisor<BITVEC_NBIT ) p->iDivisor = BITVEC_NBIT;223      rc = sqlite3BitvecSet(p, i);224      for(j=0; j<BITVEC_NINT; j++){225        if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]);226      }227      sqlite3StackFree(0, aiValues);228      return rc;229    }230  }231bitvec_set_end:232  p->nSet++;233  p->u.aHash[h] = i;234  return SQLITE_OK;235}236 237/*238** Clear the i-th bit.239**240** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage241** that BitvecClear can use to rebuilt its hash table.242*/243void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){244  if( p==0 ) return;245  assert( i>0 );246  i--;247  while( p->iDivisor ){248    u32 bin = i/p->iDivisor;249    i = i%p->iDivisor;250    p = p->u.apSub[bin];251    if (!p) {252      return;253    }254  }255  if( p->iSize<=BITVEC_NBIT ){256    p->u.aBitmap[i/BITVEC_SZELEM] &= ~(BITVEC_TELEM)(1<<(i&(BITVEC_SZELEM-1)));257  }else{258    unsigned int j;259    u32 *aiValues = pBuf;260    memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));261    memset(p->u.aHash, 0, sizeof(p->u.aHash));262    p->nSet = 0;263    for(j=0; j<BITVEC_NINT; j++){264      if( aiValues[j] && aiValues[j]!=(i+1) ){265        u32 h = BITVEC_HASH(aiValues[j]-1);266        p->nSet++;267        while( p->u.aHash[h] ){268          h++;269          if( h>=BITVEC_NINT ) h = 0;270        }271        p->u.aHash[h] = aiValues[j];272      }273    }274  }275}276 277/*278** Destroy a bitmap object.  Reclaim all memory used.279*/280void sqlite3BitvecDestroy(Bitvec *p){281  if( p==0 ) return;282  if( p->iDivisor ){283    unsigned int i;284    for(i=0; i<BITVEC_NPTR; i++){285      sqlite3BitvecDestroy(p->u.apSub[i]);286    }287  }288  sqlite3_free(p);289}290 291/*292** Return the value of the iSize parameter specified when Bitvec *p293** was created.294*/295u32 sqlite3BitvecSize(Bitvec *p){296  return p->iSize;297}298 299#ifdef SQLITE_DEBUG300/*301** Show the content of a Bitvec option and its children.  Indent302** everything by n spaces.  Add x to each bitvec value.303**304** From a debugger such as gdb, one can type:305**306**    call sqlite3ShowBitvec(p)307**308** For some Bitvec p and see a recursive view of the Bitvec's content.309*/310static void showBitvec(Bitvec *p, int n, unsigned x){311  int i;312  if( p==0 ){313    printf("NULL\n");314    return;315  }316  printf("Bitvec 0x%p iSize=%u", p, p->iSize);317  if( p->iSize<=BITVEC_NBIT ){318    printf(" bitmap\n");319    printf("%*s   bits:", n, "");320    for(i=1; i<=BITVEC_NBIT; i++){321      if( sqlite3BitvecTest(p,i) ) printf(" %u", x+(unsigned)i);322    }323    printf("\n");324  }else if( p->iDivisor==0 ){325    printf(" hash with %u entries\n", p->nSet);326    printf("%*s   bits:", n, "");327    for(i=0; i<BITVEC_NINT; i++){328      if( p->u.aHash[i] ) printf(" %u", x+(unsigned)p->u.aHash[i]);329    }330    printf("\n");331  }else{332    printf(" sub-bitvec with iDivisor=%u\n", p->iDivisor);333    for(i=0; i<BITVEC_NPTR; i++){334      if( p->u.apSub[i]==0 ) continue;335      printf("%*s   apSub[%d]=", n, "", i);336      showBitvec(p->u.apSub[i], n+4, i*p->iDivisor);337    }338  }339}340void sqlite3ShowBitvec(Bitvec *p){341  showBitvec(p, 0, 0);342}343#endif344 345#ifndef SQLITE_UNTESTABLE346/*347** Let V[] be an array of unsigned characters sufficient to hold348** up to N bits.  Let I be an integer between 0 and N.  0<=I<N.349** Then the following macros can be used to set, clear, or test350** individual bits within V.351*/352#define SETBIT(V,I)      V[I>>3] |= (1<<(I&7))353#define CLEARBIT(V,I)    V[I>>3] &= ~(BITVEC_TELEM)(1<<(I&7))354#define TESTBIT(V,I)     (V[I>>3]&(1<<(I&7)))!=0355 356 357/*358** This routine runs an extensive test of the Bitvec code.359**360** The input is an array of integers that acts as a program361** to test the Bitvec.  The integers are opcodes followed362** by 0, 1, or 3 operands, depending on the opcode.  Another363** opcode follows immediately after the last operand.364**365** There are opcodes numbered starting with 0.  0 is the366** "halt" opcode and causes the test to end.367**368**    0          Halt and return the number of errors369**    1 N S X    Set N bits beginning with S and incrementing by X370**    2 N S X    Clear N bits beginning with S and incrementing by X371**    3 N        Set N randomly chosen bits372**    4 N        Clear N randomly chosen bits373**    5 N S X    Set N bits from S increment X in array only, not in bitvec374**    6          Invoice sqlite3ShowBitvec() on the Bitvec object so far375**    7 X        Show compile-time parameters and the hash of X         376**377** The opcodes 1 through 4 perform set and clear operations are performed378** on both a Bitvec object and on a linear array of bits obtained from malloc.379** Opcode 5 works on the linear array only, not on the Bitvec.380** Opcode 5 is used to deliberately induce a fault in order to381** confirm that error detection works.  Opcodes 6 and greater are382** state output opcodes.  Opcodes 6 and greater are no-ops unless383** SQLite has been compiled with SQLITE_DEBUG.384**385** At the conclusion of the test the linear array is compared386** against the Bitvec object.  If there are any differences,387** an error is returned.  If they are the same, zero is returned.388**389** If a memory allocation error occurs, return -1.390**391** sz is the size of the Bitvec.  Or if sz is negative, make the size392** 2*(unsigned)(-sz) and disabled the linear vector check.393*/394int sqlite3BitvecBuiltinTest(int sz, int *aOp){395  Bitvec *pBitvec = 0;396  unsigned char *pV = 0;397  int rc = -1;398  int i, nx, pc, op;399  void *pTmpSpace;400 401  /* Allocate the Bitvec to be tested and a linear array of402  ** bits to act as the reference */403  if( sz<=0 ){404    pBitvec = sqlite3BitvecCreate( 2*(unsigned)(-sz) );405    pV = 0;406  }else{407    pBitvec = sqlite3BitvecCreate( sz );408    pV = sqlite3MallocZero( (7+(i64)sz)/8 + 1 );409  }410  pTmpSpace = sqlite3_malloc64(BITVEC_SZ);411  if( pBitvec==0 || pTmpSpace==0 || (pV==0 && sz>0) ) goto bitvec_end;412 413  /* NULL pBitvec tests */414  sqlite3BitvecSet(0, 1);415  sqlite3BitvecClear(0, 1, pTmpSpace);416 417  /* Run the program */418  pc = i = 0;419  while( (op = aOp[pc])!=0 ){420    if( op>=6 ){421#ifdef SQLITE_DEBUG422      if( op==6 ){423        sqlite3ShowBitvec(pBitvec);424      }else if( op==7 ){425        printf("BITVEC_SZ     = %d (%d by sizeof)\n",426               BITVEC_SZ, (int)sizeof(Bitvec));427        printf("BITVEC_USIZE  = %d\n", (int)BITVEC_USIZE);428        printf("BITVEC_NELEM  = %d\n", (int)BITVEC_NELEM);429        printf("BITVEC_NBIT   = %d\n", (int)BITVEC_NBIT);430        printf("BITVEC_NINT   = %d\n", (int)BITVEC_NINT);431        printf("BITVEC_MXHASH = %d\n", (int)BITVEC_MXHASH);432        printf("BITVEC_NPTR   = %d\n", (int)BITVEC_NPTR);433      }434#endif435      pc++;436      continue;437    }438    switch( op ){439      case 1:440      case 2:441      case 5: {442        nx = 4;443        i = aOp[pc+2] - 1;444        aOp[pc+2] += aOp[pc+3];445        break;446      }447      case 3:448      case 4:449      default: {450        nx = 2;451        sqlite3_randomness(sizeof(i), &i);452        break;453      }454    }455    if( (--aOp[pc+1]) > 0 ) nx = 0;456    pc += nx;457    i = (i & 0x7fffffff)%sz;458    if( (op & 1)!=0 ){459      if( pV ) SETBIT(pV, (i+1));460      if( op!=5 ){461        if( sqlite3BitvecSet(pBitvec, i+1) ) goto bitvec_end;462      }463    }else{464      if( pV ) CLEARBIT(pV, (i+1));465      sqlite3BitvecClear(pBitvec, i+1, pTmpSpace);466    }467  }468 469  /* Test to make sure the linear array exactly matches the470  ** Bitvec object.  Start with the assumption that they do471  ** match (rc==0).  Change rc to non-zero if a discrepancy472  ** is found.473  */474  if( pV ){475    rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1)476            + sqlite3BitvecTest(pBitvec, 0)477            + (sqlite3BitvecSize(pBitvec) - sz);478    for(i=1; i<=sz; i++){479      if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){480        rc = i;481        break;482      }483    }484  }else{485    rc = 0;486  }487 488  /* Free allocated structure */489bitvec_end:490  sqlite3_free(pTmpSpace);491  sqlite3_free(pV);492  sqlite3BitvecDestroy(pBitvec);493  return rc;494}495#endif /* SQLITE_UNTESTABLE */496