SQLite4
Check-in [3cb223f975]
Not logged in

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 | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3cb223f975a537145a10d1781e920ecc932ff45d
User & Date: drh 2013-07-31 15:32:34
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
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/kvmem.c.

251
252
253
254
255
256
257






258
259
260
261
262
263
264
...
334
335
336
337
338
339
340

341
342
343
344
345
346

347
348
349
350
351
352
353
...
483
484
485
486
487
488
489

490
491
492
493
494
495
496
...
536
537
538
539
540
541
542

543
544
545
546
547
548
549
...
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
...
826
827
828
829
830
831
832



833

834
835
836
837
838
839
840
841
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).
................................................................................
  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 
................................................................................
}
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 ){
................................................................................
** 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;
................................................................................
          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;
      }
    }
................................................................................
  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;
  }







>
>
>
>
>
>







 







>
|
|
|
|
|
|
>







 







>







 







>







 







|







 







>
>
>
|
>
|







251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
...
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
...
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
...
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
...
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
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).
................................................................................
  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 
................................................................................
}
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 ){
................................................................................
** 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;
................................................................................
          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;
      }
    }
................................................................................
  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;
  }