Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Enhance kvmem to honor the SQLITE4_KVOPEN_NO_TRANSACTIONS flag. This makes kvmem significantly faster when used to implement ORDER BY with LIMIT.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3cb223f975a537145a10d1781e920ecc932ff45d
User & Date: drh 2013-07-31 15:32:34.957
Context
2013-07-31
17:43
Extra tests for sqlite_kvstore. check-in: 9ce1a04efd user: dan tags: trunk
15:32
Enhance kvmem to honor the SQLITE4_KVOPEN_NO_TRANSACTIONS flag. This makes kvmem significantly faster when used to implement ORDER BY with LIMIT. check-in: 3cb223f975 user: drh tags: trunk
14:38
Allow writing to the sqlite_kvstore if "PRAGMA writable_schema" is set. check-in: 874278817a user: dan tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/kvmem.c.
251
252
253
254
255
256
257






258
259
260
261
262
263
264
static void kvmemClearTree(sqlite4_env *pEnv, KVMemNode *pNode){
  if( pNode==0 ) return;
  kvmemClearTree(pEnv, pNode->pBefore);
  kvmemClearTree(pEnv, pNode->pAfter);
  kvmemNodeUnref(pEnv, pNode);
}







/*
** End of utilities
***************************************************************************
** Low-level operations on the tree
*/

/* Find the first node (the one with the smallest key).







>
>
>
>
>
>







251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
static void kvmemClearTree(sqlite4_env *pEnv, KVMemNode *pNode){
  if( pNode==0 ) return;
  kvmemClearTree(pEnv, pNode->pBefore);
  kvmemClearTree(pEnv, pNode->pAfter);
  kvmemNodeUnref(pEnv, pNode);
}

/*
** Return true if transactions are preserved
*/
#define kvmemTransactional(P) \
   (((P)->openFlags & SQLITE4_KVOPEN_NO_TRANSACTIONS)==0)

/*
** End of utilities
***************************************************************************
** Low-level operations on the tree
*/

/* Find the first node (the one with the smallest key).
334
335
336
337
338
339
340

341
342
343
344
345
346

347
348
349
350
351
352
353
  assert( p->base.iTransLevel>=2 );
  pNode = sqlite4_malloc(p->base.pEnv, sizeof(*pNode)+nKey-2 );
  if( pNode ){
    memset(pNode, 0, sizeof(*pNode));
    memcpy(pNode->aKey, aKey, nKey);
    pNode->nKey = nKey;
    pNode->nRef = 1;

    pChng = kvmemNewChng(p, pNode);
    if( pChng==0 ){
      sqlite4_free(p->base.pEnv, pNode);
      pNode = 0;
    }
    assert( pChng==0 || pChng->pData==0 );

  }
  return pNode;
}

#ifdef SQLITE4_DEBUG
/*
** Return the number of times that node pNode occurs in the sub-tree 







>
|
|
|
|
|
|
>







340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  assert( p->base.iTransLevel>=2 );
  pNode = sqlite4_malloc(p->base.pEnv, sizeof(*pNode)+nKey-2 );
  if( pNode ){
    memset(pNode, 0, sizeof(*pNode));
    memcpy(pNode->aKey, aKey, nKey);
    pNode->nKey = nKey;
    pNode->nRef = 1;
    if( kvmemTransactional(p) ){
      pChng = kvmemNewChng(p, pNode);
      if( pChng==0 ){
        sqlite4_free(p->base.pEnv, pNode);
        pNode = 0;
      }
      assert( pChng==0 || pChng->pData==0 );
    }
  }
  return pNode;
}

#ifdef SQLITE4_DEBUG
/*
** Return the number of times that node pNode occurs in the sub-tree 
483
484
485
486
487
488
489

490
491
492
493
494
495
496
}
static int kvmemCommitPhaseTwo(KVStore *pKVStore, int iLevel){
  KVMem *p = (KVMem*)pKVStore;
  assert( p->iMagicKVMemBase==SQLITE4_KVMEMBASE_MAGIC );
  assert( iLevel>=0 );
  assert( iLevel<p->base.iTransLevel );
  assertUpPointers(p->pRoot);

  while( p->base.iTransLevel>iLevel && p->base.iTransLevel>1 ){
    KVMemChng *pChng, *pNext;

    if( iLevel<2 ){
      for(pChng=p->apLog[p->base.iTransLevel-2]; pChng; pChng=pNext){
        KVMemNode *pNode = pChng->pNode;
        if( pNode->pData ){







>







491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
}
static int kvmemCommitPhaseTwo(KVStore *pKVStore, int iLevel){
  KVMem *p = (KVMem*)pKVStore;
  assert( p->iMagicKVMemBase==SQLITE4_KVMEMBASE_MAGIC );
  assert( iLevel>=0 );
  assert( iLevel<p->base.iTransLevel );
  assertUpPointers(p->pRoot);
  if( !kvmemTransactional(p) ) return SQLITE4_OK;
  while( p->base.iTransLevel>iLevel && p->base.iTransLevel>1 ){
    KVMemChng *pChng, *pNext;

    if( iLevel<2 ){
      for(pChng=p->apLog[p->base.iTransLevel-2]; pChng; pChng=pNext){
        KVMemNode *pNode = pChng->pNode;
        if( pNode->pData ){
536
537
538
539
540
541
542

543
544
545
546
547
548
549
** After this routine returns successfully, the transaction level will be
** equal to iLevel.
*/
static int kvmemRollback(KVStore *pKVStore, int iLevel){
  KVMem *p = (KVMem*)pKVStore;
  assert( p->iMagicKVMemBase==SQLITE4_KVMEMBASE_MAGIC );
  assert( iLevel>=0 );

  while( p->base.iTransLevel>iLevel && p->base.iTransLevel>1 ){
    KVMemChng *pChng, *pNext;
    for(pChng=p->apLog[p->base.iTransLevel-2]; pChng; pChng=pNext){
      KVMemNode *pNode = pChng->pNode;
      if( pChng->pData || pChng->oldTrans>0 ){
        kvmemDataUnref(p->base.pEnv, pNode->pData);
        pNode->pData = pChng->pData;







>







545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
** After this routine returns successfully, the transaction level will be
** equal to iLevel.
*/
static int kvmemRollback(KVStore *pKVStore, int iLevel){
  KVMem *p = (KVMem*)pKVStore;
  assert( p->iMagicKVMemBase==SQLITE4_KVMEMBASE_MAGIC );
  assert( iLevel>=0 );
  if( !kvmemTransactional(p) ) return SQLITE4_OK;
  while( p->base.iTransLevel>iLevel && p->base.iTransLevel>1 ){
    KVMemChng *pChng, *pNext;
    for(pChng=p->apLog[p->base.iTransLevel-2]; pChng; pChng=pNext){
      KVMemNode *pNode = pChng->pNode;
      if( pChng->pData || pChng->oldTrans>0 ){
        kvmemDataUnref(p->base.pEnv, pNode->pData);
        pNode->pData = pChng->pData;
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
          if( pNew==0 ) goto KVMemReplace_nomem;
          pNew->pUp = pNode;
          break;
        }
      }else{
        if( pNode->mxTrans==p->base.iTransLevel ){
          kvmemDataUnref(p->base.pEnv, pNode->pData);
        }else{
          pChng = kvmemNewChng(p, pNode);
          if( pChng==0 ) goto KVMemReplace_nomem;
        }
        pNode->pData = pData;
        return SQLITE4_OK;
      }
    }







|







633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
          if( pNew==0 ) goto KVMemReplace_nomem;
          pNew->pUp = pNode;
          break;
        }
      }else{
        if( pNode->mxTrans==p->base.iTransLevel ){
          kvmemDataUnref(p->base.pEnv, pNode->pData);
        }else if( kvmemTransactional(p) ){
          pChng = kvmemNewChng(p, pNode);
          if( pChng==0 ) goto KVMemReplace_nomem;
        }
        pNode->pData = pData;
        return SQLITE4_OK;
      }
    }
826
827
828
829
830
831
832



833

834
835
836
837
838
839
840
841
  pCur = (KVMemCursor*)pKVCursor;
  assert( pCur->iMagicKVMemCur==SQLITE4_KVMEMCUR_MAGIC );
  p = pCur->pOwner;
  assert( p->iMagicKVMemBase==SQLITE4_KVMEMBASE_MAGIC );
  assert( p->base.iTransLevel>=2 );
  pNode = pCur->pNode;
  if( pNode==0 ) return SQLITE4_OK;



  if( pNode->pData==0 ) return SQLITE4_OK;

  if( pNode->mxTrans<p->base.iTransLevel ){
    pChng = kvmemNewChng(p, pNode);
    if( pChng==0 ) return SQLITE4_NOMEM;
    assert( pNode->pData==0 );
  }else{
    kvmemDataUnref(pCur->base.pEnv, pNode->pData);
    pNode->pData = 0;
  }







>
>
>
|
>
|







836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
  pCur = (KVMemCursor*)pKVCursor;
  assert( pCur->iMagicKVMemCur==SQLITE4_KVMEMCUR_MAGIC );
  p = pCur->pOwner;
  assert( p->iMagicKVMemBase==SQLITE4_KVMEMBASE_MAGIC );
  assert( p->base.iTransLevel>=2 );
  pNode = pCur->pNode;
  if( pNode==0 ) return SQLITE4_OK;
  if( !kvmemTransactional(p) ){
    pCur->pNode = 0;
    kvmemRemoveNode(p, pNode);
  }else if( pNode->pData==0 ){
    /* no-op */
  }else if( pNode->mxTrans<p->base.iTransLevel ){
    pChng = kvmemNewChng(p, pNode);
    if( pChng==0 ) return SQLITE4_NOMEM;
    assert( pNode->pData==0 );
  }else{
    kvmemDataUnref(pCur->base.pEnv, pNode->pData);
    pNode->pData = 0;
  }