SQLite4
Check-in [8915d39dab2d0ff8906328eb0cd3df1cecad65bc]
Not logged in

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

Overview
SHA1 Hash:8915d39dab2d0ff8906328eb0cd3df1cecad65bc
Date: 2012-11-15 18:45:06
User: dan
Comment:Update the lsm code so that it matches lsmusr.wiki.
Tags And Properties
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to lsm-test/lsmtest1.c

405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  /* Start the test case, open a database and allocate the datasource. */
  pDb = testOpen(zSystem, 1, &rc);
  pData = testDatasourceNew(&p->defn);
  rc = testControlDb(&pControl);

  if( tdb_lsm(pDb) ){
    int nBuf = 32 * 1024 * 1024;
    lsm_config(tdb_lsm(pDb), LSM_CONFIG_WRITE_BUFFER, &nBuf);
  }

  for(i=0; rc==0 && i<p->nIter; i++){
    void *pKey1; int nKey1;
    void *pKey2; int nKey2;
    int ii;
    int nRange = MIN(p->nIter*p->nWrite, p->nRange);







|







405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  /* Start the test case, open a database and allocate the datasource. */
  pDb = testOpen(zSystem, 1, &rc);
  pData = testDatasourceNew(&p->defn);
  rc = testControlDb(&pControl);

  if( tdb_lsm(pDb) ){
    int nBuf = 32 * 1024 * 1024;
    lsm_config(tdb_lsm(pDb), LSM_CONFIG_AUTOFLUSH, &nBuf);
  }

  for(i=0; rc==0 && i<p->nIter; i++){
    void *pKey1; int nKey1;
    void *pKey2; int nKey2;
    int ii;
    int nRange = MIN(p->nIter*p->nWrite, p->nRange);

Changes to lsm-test/lsmtest2.c

263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  int iDot = 0;
  Datasource *pData;
  CksumDb *pCksumDb;
  TestDb *pDb;
  char *zCfg;

  const char *azConfig[2] = {
    "page_size=1024 block_size=65536 write_buffer=16384 safety=2 mmap=0", 
    "page_size=1024 block_size=65536 write_buffer=16384 safety=2 "
    " compression=1 mmap=0"
  };
  assert( bCompress==0 || bCompress==1 );

  /* Allocate datasource. And calculate the expected checksums. */
  pData = testDatasourceNew(&defn);
  pCksumDb = testCksumArrayNew(pData, nRow, nRow, 1);

  /* Setup and save the initial database. */

  zCfg = testMallocPrintf("%s nmerge=7", azConfig[bCompress]);
  testSetupSavedLsmdb(zCfg, DBNAME, pData, 5000, pRc);
  testFree(zCfg);

  for(i=0; i<nIter && *pRc==0; i++){
    int iWork;
    int testrc = 0;








|
|










|







263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  int iDot = 0;
  Datasource *pData;
  CksumDb *pCksumDb;
  TestDb *pDb;
  char *zCfg;

  const char *azConfig[2] = {
    "page_size=1024 block_size=65536 autoflush=16384 safety=2 mmap=0", 
    "page_size=1024 block_size=65536 autoflush=16384 safety=2 "
    " compression=1 mmap=0"
  };
  assert( bCompress==0 || bCompress==1 );

  /* Allocate datasource. And calculate the expected checksums. */
  pData = testDatasourceNew(&defn);
  pCksumDb = testCksumArrayNew(pData, nRow, nRow, 1);

  /* Setup and save the initial database. */

  zCfg = testMallocPrintf("%s automerge=7", azConfig[bCompress]);
  testSetupSavedLsmdb(zCfg, DBNAME, pData, 5000, pRc);
  testFree(zCfg);

  for(i=0; i<nIter && *pRc==0; i++){
    int iWork;
    int testrc = 0;

Changes to lsm-test/lsmtest6.c

421
422
423
424
425
426
427
428
429
430
431
432
433
434
435

  testDeleteLsmdb(LSMTEST6_TESTDB);
  rc = lsm_new(tdb_lsm_env(), &pDb);
  if( rc==LSM_OK ) rc = lsm_open(pDb, LSMTEST6_TESTDB);

  lsm_config(pDb, LSM_CONFIG_BLOCK_SIZE, &nBlocksize); 
  lsm_config(pDb, LSM_CONFIG_PAGE_SIZE, &nPagesize); 
  lsm_config(pDb, LSM_CONFIG_WRITE_BUFFER, &nWritebuffer); 

  pData = getDatasource();
  for(ii=0; rc==LSM_OK && ii<5000; ii++){
    void *pKey; int nKey;
    void *pVal; int nVal;
    testDatasourceEntry(pData, ii, &pKey, &nKey, &pVal, &nVal);
    lsm_insert(pDb, pKey, nKey, pVal, nVal);







|







421
422
423
424
425
426
427
428
429
430
431
432
433
434
435

  testDeleteLsmdb(LSMTEST6_TESTDB);
  rc = lsm_new(tdb_lsm_env(), &pDb);
  if( rc==LSM_OK ) rc = lsm_open(pDb, LSMTEST6_TESTDB);

  lsm_config(pDb, LSM_CONFIG_BLOCK_SIZE, &nBlocksize); 
  lsm_config(pDb, LSM_CONFIG_PAGE_SIZE, &nPagesize); 
  lsm_config(pDb, LSM_CONFIG_AUTOFLUSH, &nWritebuffer); 

  pData = getDatasource();
  for(ii=0; rc==LSM_OK && ii<5000; ii++){
    void *pKey; int nKey;
    void *pVal; int nVal;
    testDatasourceEntry(pData, ii, &pKey, &nKey, &pVal, &nVal);
    lsm_insert(pDb, pKey, nKey, pVal, nVal);

Changes to lsm-test/lsmtest8.c

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  testWriteDatasourceRange(pDb, pData, pStep->iInsStart, pStep->nIns, pRc);
  testDeleteDatasourceRange(pDb, pData, pStep->iDelStart, pStep->nDel, pRc);
  if( *pRc==0 ){
    int nSave = -1;
    int nBuf = 64;
    lsm_db *db = tdb_lsm(pDb);

    lsm_config(db, LSM_CONFIG_WRITE_BUFFER, &nSave);
    lsm_config(db, LSM_CONFIG_WRITE_BUFFER, &nBuf);
    lsm_begin(db, 1);
    lsm_commit(db, 0);
    lsm_config(db, LSM_CONFIG_WRITE_BUFFER, &nSave);

    *pRc = lsm_work(db, 0, 0, 0);
    if( *pRc==0 ){
      *pRc = lsm_checkpoint(db, 0);
    }
  }
}
................................................................................
      rc = 1;
    }
    testFree(pHdr);

    if( rc==0 ){
      int nBuf = 64;
      db = tdb_lsm(pDb);
      lsm_config(db, LSM_CONFIG_WRITE_BUFFER, &nBuf);
      lsm_begin(db, 1);
      lsm_commit(db, 0);
      rc = lsm_work(db, 0, 0, 0);
    }

    testCksumDatabase(pDb, zCksum2);
    testCompareStr(zCksum, zCksum2, &rc);







|
|


|







 







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  testWriteDatasourceRange(pDb, pData, pStep->iInsStart, pStep->nIns, pRc);
  testDeleteDatasourceRange(pDb, pData, pStep->iDelStart, pStep->nDel, pRc);
  if( *pRc==0 ){
    int nSave = -1;
    int nBuf = 64;
    lsm_db *db = tdb_lsm(pDb);

    lsm_config(db, LSM_CONFIG_AUTOFLUSH, &nSave);
    lsm_config(db, LSM_CONFIG_AUTOFLUSH, &nBuf);
    lsm_begin(db, 1);
    lsm_commit(db, 0);
    lsm_config(db, LSM_CONFIG_AUTOFLUSH, &nSave);

    *pRc = lsm_work(db, 0, 0, 0);
    if( *pRc==0 ){
      *pRc = lsm_checkpoint(db, 0);
    }
  }
}
................................................................................
      rc = 1;
    }
    testFree(pHdr);

    if( rc==0 ){
      int nBuf = 64;
      db = tdb_lsm(pDb);
      lsm_config(db, LSM_CONFIG_AUTOFLUSH, &nBuf);
      lsm_begin(db, 1);
      lsm_commit(db, 0);
      rc = lsm_work(db, 0, 0, 0);
    }

    testCksumDatabase(pDb, zCksum2);
    testCompareStr(zCksum, zCksum2, &rc);

Changes to lsm-test/lsmtest_main.c

489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
  return (nFail!=0);
}

static lsm_db *configure_lsm_db(TestDb *pDb){
  lsm_db *pLsm;
  pLsm = tdb_lsm(pDb);
  if( pLsm ){
    tdb_lsm_config_str(pDb, "mmap=1 autowork=1 nmerge=4 worker_nmerge=4");
  }
  return pLsm;
}

#define ST_REPEAT  0
#define ST_WRITE   1
#define ST_PAUSE   2







|







489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
  return (nFail!=0);
}

static lsm_db *configure_lsm_db(TestDb *pDb){
  lsm_db *pLsm;
  pLsm = tdb_lsm(pDb);
  if( pLsm ){
    tdb_lsm_config_str(pDb, "mmap=1 autowork=1 automerge=4 worker_automerge=4");
  }
  return pLsm;
}

#define ST_REPEAT  0
#define ST_WRITE   1
#define ST_PAUSE   2

Changes to lsm-test/lsmtest_tdb3.c

485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
...
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
...
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
....
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
  int nVal
){
  LsmDb *pDb = (LsmDb *)pTestDb;

  if( pDb->aWorker ){
    int nLimit = -1;
    int nSleep = 0;
    lsm_config(pDb->db, LSM_CONFIG_WRITE_BUFFER, &nLimit);
    do {
      int bOld, nNew, rc;
      rc = lsm_tree_size(pDb->db, &bOld, &nNew);
      if( rc!=LSM_OK ) return rc;
      if( bOld==0 || nNew<nLimit ) break;
      usleep(1000);
      nSleep += 1;
    }while( 1 );
#if 0
    if( nSleep ) printf("nSleep=%d\n", nSleep);
................................................................................
  int *pnThread
){
  struct CfgParam {
    const char *zParam;
    int bWorker;
    int eParam;
  } aParam[] = {
    { "write_buffer",     0, LSM_CONFIG_WRITE_BUFFER },
    { "page_size",        0, LSM_CONFIG_PAGE_SIZE },
    { "block_size",       0, LSM_CONFIG_BLOCK_SIZE },
    { "safety",           0, LSM_CONFIG_SAFETY },
    { "autowork",         0, LSM_CONFIG_AUTOWORK },
    { "autocheckpoint",   0, LSM_CONFIG_AUTOCHECKPOINT },
    { "log_size",         0, LSM_CONFIG_LOG_SIZE },
    { "mmap",             0, LSM_CONFIG_MMAP },
    { "use_log",          0, LSM_CONFIG_USE_LOG },
    { "nmerge",           0, LSM_CONFIG_NMERGE },
    { "max_freelist",     0, LSM_CONFIG_MAX_FREELIST },
    { "multi_proc",       0, LSM_CONFIG_MULTIPLE_PROCESSES },
    { "worker_nmerge",    1, LSM_CONFIG_NMERGE },
    { "test_no_recovery", 0, TEST_NO_RECOVERY },
    { "threads",          0, TEST_THREADS },
#ifdef HAVE_ZLIB
    { "compression",      0, TEST_COMPRESSION },
#endif
    { 0, 0 }
  };
................................................................................

int test_lsm_lomem_open(
  const char *zFilename, 
  int bClear, 
  TestDb **ppDb
){
  const char *zCfg = 
    "page_size=256 block_size=65536 write_buffer=16384 "
    "max_freelist=2 autocheckpoint=32768 "
    "mmap=0 "
  ;
  return testLsmOpen(zCfg, zFilename, bClear, ppDb);
}

int test_lsm_zip_open(
  const char *zFilename, 
  int bClear, 
  TestDb **ppDb
){
  const char *zCfg = 
    "page_size=256 block_size=65536 write_buffer=16384 "
    "max_freelist=2 autocheckpoint=32768 compression=1"
    "mmap=0 "
  ;
  return testLsmOpen(zCfg, zFilename, bClear, ppDb);
}

lsm_db *tdb_lsm(TestDb *pDb){
................................................................................
    pthread_mutex_unlock(&p->worker_mutex);

    if( p->bCkpt ){
      rc = lsm_checkpoint(pWorker, 0);
    }else{
      int nWrite = 0;             /* Pages written by lsm_work() call */
      int nAuto = -1;             /* Configured AUTOCHECKPOINT value */
      int nLimit = -1;            /* Configured WRITE_BUFFER value */

      lsm_config(pWorker, LSM_CONFIG_WRITE_BUFFER, &nLimit);
      lsm_config(pWorker, LSM_CONFIG_AUTOCHECKPOINT, &nAuto);
      do {
        int nSleep = 0;
        lsm_ckpt_size(pWorker, &nCkpt);
        while( nAuto==0 && nCkpt>(nLimit*4) ){
          usleep(1000);
          mt_signal_worker(p->pDb, 1);
          nSleep++;
          lsm_ckpt_size(pWorker, &nCkpt);
        }
#if 0
          if( nSleep ) printf("nLimit=%d nSleep=%d (worker)\n", nLimit, nSleep);
#endif

        rc = lsm_work(pWorker, p->lsm_work_flags, p->lsm_work_npage, &nWrite);
        if( nAuto==0 && nWrite && rc==LSM_OK ) mt_signal_worker(p->pDb, 1);







|


|







 







|








|


|







 







|












|







 







|

|



|




|







485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
...
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
...
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
....
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
  int nVal
){
  LsmDb *pDb = (LsmDb *)pTestDb;

  if( pDb->aWorker ){
    int nLimit = -1;
    int nSleep = 0;
    lsm_config(pDb->db, LSM_CONFIG_AUTOFLUSH, &nLimit);
    do {
      int bOld, nNew, rc;
      rc = lsm_info(pDb->db, LSM_INFO_TREE_SIZE, &bOld, &nNew);
      if( rc!=LSM_OK ) return rc;
      if( bOld==0 || nNew<nLimit ) break;
      usleep(1000);
      nSleep += 1;
    }while( 1 );
#if 0
    if( nSleep ) printf("nSleep=%d\n", nSleep);
................................................................................
  int *pnThread
){
  struct CfgParam {
    const char *zParam;
    int bWorker;
    int eParam;
  } aParam[] = {
    { "autoflush",        0, LSM_CONFIG_AUTOFLUSH },
    { "page_size",        0, LSM_CONFIG_PAGE_SIZE },
    { "block_size",       0, LSM_CONFIG_BLOCK_SIZE },
    { "safety",           0, LSM_CONFIG_SAFETY },
    { "autowork",         0, LSM_CONFIG_AUTOWORK },
    { "autocheckpoint",   0, LSM_CONFIG_AUTOCHECKPOINT },
    { "log_size",         0, LSM_CONFIG_LOG_SIZE },
    { "mmap",             0, LSM_CONFIG_MMAP },
    { "use_log",          0, LSM_CONFIG_USE_LOG },
    { "automerge",        0, LSM_CONFIG_AUTOMERGE },
    { "max_freelist",     0, LSM_CONFIG_MAX_FREELIST },
    { "multi_proc",       0, LSM_CONFIG_MULTIPLE_PROCESSES },
    { "worker_automerge", 1, LSM_CONFIG_AUTOMERGE },
    { "test_no_recovery", 0, TEST_NO_RECOVERY },
    { "threads",          0, TEST_THREADS },
#ifdef HAVE_ZLIB
    { "compression",      0, TEST_COMPRESSION },
#endif
    { 0, 0 }
  };
................................................................................

int test_lsm_lomem_open(
  const char *zFilename, 
  int bClear, 
  TestDb **ppDb
){
  const char *zCfg = 
    "page_size=256 block_size=65536 autoflush=16384 "
    "max_freelist=2 autocheckpoint=32768 "
    "mmap=0 "
  ;
  return testLsmOpen(zCfg, zFilename, bClear, ppDb);
}

int test_lsm_zip_open(
  const char *zFilename, 
  int bClear, 
  TestDb **ppDb
){
  const char *zCfg = 
    "page_size=256 block_size=65536 autoflush=16384 "
    "max_freelist=2 autocheckpoint=32768 compression=1"
    "mmap=0 "
  ;
  return testLsmOpen(zCfg, zFilename, bClear, ppDb);
}

lsm_db *tdb_lsm(TestDb *pDb){
................................................................................
    pthread_mutex_unlock(&p->worker_mutex);

    if( p->bCkpt ){
      rc = lsm_checkpoint(pWorker, 0);
    }else{
      int nWrite = 0;             /* Pages written by lsm_work() call */
      int nAuto = -1;             /* Configured AUTOCHECKPOINT value */
      int nLimit = -1;            /* Configured AUTOFLUSH value */

      lsm_config(pWorker, LSM_CONFIG_AUTOFLUSH, &nLimit);
      lsm_config(pWorker, LSM_CONFIG_AUTOCHECKPOINT, &nAuto);
      do {
        int nSleep = 0;
        lsm_info(pWorker, LSM_INFO_CHECKPOINT_SIZE, &nCkpt);
        while( nAuto==0 && nCkpt>(nLimit*4) ){
          usleep(1000);
          mt_signal_worker(p->pDb, 1);
          nSleep++;
          lsm_info(pWorker, LSM_INFO_CHECKPOINT_SIZE, &nCkpt);
        }
#if 0
          if( nSleep ) printf("nLimit=%d nSleep=%d (worker)\n", nLimit, nSleep);
#endif

        rc = lsm_work(pWorker, p->lsm_work_flags, p->lsm_work_npage, &nWrite);
        if( nAuto==0 && nWrite && rc==LSM_OK ) mt_signal_worker(p->pDb, 1);

Changes to src/lsm.h

141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
...
358
359
360
361
362
363
364






















365
366
367
368
369
370
371
372
373
374


375
376
377
378
379
380
381
...
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
...
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
** The lsm_config() function is used to configure a database connection.
*/
int lsm_config(lsm_db *, int, ...);

/*
** The following values may be passed as the second argument to lsm_config().
**
** LSM_CONFIG_WRITE_BUFFER:
**   A read/write integer parameter. This value determines the maximum amount
**   of space (in bytes) used to accumulate writes in main-memory before 
**   they are flushed to a level 0 segment.
**
** LSM_CONFIG_PAGE_SIZE:
**   A read/write integer parameter. This parameter may only be set before
**   lsm_open() has been called.
................................................................................
**   A read/write integer parameter. True to use mmap() to access the 
**   database file. False otherwise.
**
** LSM_CONFIG_USE_LOG:
**   A read/write boolean parameter. True (the default) to use the log
**   file normally. False otherwise.
**
** LSM_CONFIG_NMERGE:
**   A read/write integer parameter. The minimum number of segments to
**   merge together at a time. Default value 4.
**
** LSM_CONFIG_MAX_FREELIST:
**   A read/write integer parameter. The maximum number of free-list 
**   entries that are stored in a database checkpoint (the others are
**   stored elsewhere in the database).
................................................................................
**   This option may only be used before lsm_open() is called. Invoking it
**   after lsm_open() has been called results in an LSM_MISUSE error.
**
** LSM_CONFIG_GET_COMPRESSION:
**   Query the compression methods used to compress and decompress database
**   content.
*/
#define LSM_CONFIG_WRITE_BUFFER        1
#define LSM_CONFIG_PAGE_SIZE           2
#define LSM_CONFIG_SAFETY              3
#define LSM_CONFIG_BLOCK_SIZE          4
#define LSM_CONFIG_AUTOWORK            5
#define LSM_CONFIG_LOG_SIZE            6
#define LSM_CONFIG_MMAP                7
#define LSM_CONFIG_USE_LOG             8
#define LSM_CONFIG_NMERGE              9
#define LSM_CONFIG_MAX_FREELIST       10
#define LSM_CONFIG_MULTIPLE_PROCESSES 11
#define LSM_CONFIG_AUTOCHECKPOINT     12
#define LSM_CONFIG_SET_COMPRESSION    13
#define LSM_CONFIG_GET_COMPRESSION    14

#define LSM_SAFETY_OFF    0
................................................................................
**   to is populated with a pointer to a nul-terminated string containing
**   the string representation of a Tcl data-structure. The returned 
**   string should be eventually freed by the caller using lsm_free().
**
**   The Tcl structure returned is a list containing one element for each
**   free block in the database. The element itself consists of two 
**   integers - the block number and the id of the snapshot that freed it.






















*/
#define LSM_INFO_NWRITE           1
#define LSM_INFO_NREAD            2
#define LSM_INFO_DB_STRUCTURE     3
#define LSM_INFO_LOG_STRUCTURE    4
#define LSM_INFO_ARRAY_STRUCTURE  5
#define LSM_INFO_PAGE_ASCII_DUMP  6
#define LSM_INFO_PAGE_HEX_DUMP    7
#define LSM_INFO_FREELIST         8
#define LSM_INFO_ARRAY_PAGES      9




/* 
** CAPI: Opening and Closing Write Transactions
**
** These functions are used to open and close transactions and nested 
** sub-transactions.
................................................................................
** error code if an error occurs or LSM_OK otherwise.
**
** If the current snapshot has already been checkpointed, calling this 
** function is a no-op. In this case if pnByte is not NULL, *pnByte is
** set to 0. Or, if the current snapshot is successfully checkpointed
** by this function and pbCkpt is not NULL, *pnByte is set to the number
** of bytes written to the database file since the previous checkpoint
** (the same measure as returned by lsm_ckpt_size()).
*/
int lsm_checkpoint(lsm_db *pDb, int *pnByte);

/*
** CAPI: Opening and Closing Database Cursors
**
** Open and close a database cursor.
................................................................................
void lsm_config_log(lsm_db *, void (*)(void *, int, const char *), void *);

/*
** Configure a callback that is invoked if the database connection ever
** writes to the database file.
*/
void lsm_config_work_hook(lsm_db *, void (*)(lsm_db *, void *), void *);

/*
** The lsm_tree_size() function reports on the current state of the 
** in-memory tree data structure. 
**
** At any time, there are either one or two tree structures held in shared
** memory that new database clients will access (there may also be additional 
** tree structures being used by older clients - this API does not provide
** information on them). One tree structure - the current tree - is used to
** accumulate new data written to the database. The other tree structure - the 
** old tree - is a read-only tree holding older data and may be flushed to disk
** at any time.
**
** If successful, this function sets *pnNew to the number of bytes of shared
** memory space used by the current tree. *pbOld is set to true if the old 
** tree exists, or false if it does not. 
**
** If no error occurs, LSM_OK is returned. Otherwise an LSM error code.
**
** RACE CONDITION:
**   Describe the race condition this function is subject to. 
*/
int lsm_tree_size(lsm_db *, int *pbOld, int *pnNew);

/*
** This function is used to query the amount of data that has been written
** to the database file but not checkpointed (synced). If successful, *pnByte
** is set to the number of bytes before returning.
**
** LSM_OK is returned if successful. Or if an error occurs, an LSM error
** code is returned.
**
** RACE CONDITION:
**   Describe the race condition this function is subject to. Or remove
**   it somehow.
*/
int lsm_ckpt_size(lsm_db *, int *pnByte);


/* ENDOFAPI */
#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif /* ifndef _LSM_H */







|







 







|







 







|







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










>
>







 







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
...
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
...
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
...
595
596
597
598
599
600
601






































602
603
604
605
606
607
** The lsm_config() function is used to configure a database connection.
*/
int lsm_config(lsm_db *, int, ...);

/*
** The following values may be passed as the second argument to lsm_config().
**
** LSM_CONFIG_AUTOFLUSH:
**   A read/write integer parameter. This value determines the maximum amount
**   of space (in bytes) used to accumulate writes in main-memory before 
**   they are flushed to a level 0 segment.
**
** LSM_CONFIG_PAGE_SIZE:
**   A read/write integer parameter. This parameter may only be set before
**   lsm_open() has been called.
................................................................................
**   A read/write integer parameter. True to use mmap() to access the 
**   database file. False otherwise.
**
** LSM_CONFIG_USE_LOG:
**   A read/write boolean parameter. True (the default) to use the log
**   file normally. False otherwise.
**
** LSM_CONFIG_AUTOMERGE:
**   A read/write integer parameter. The minimum number of segments to
**   merge together at a time. Default value 4.
**
** LSM_CONFIG_MAX_FREELIST:
**   A read/write integer parameter. The maximum number of free-list 
**   entries that are stored in a database checkpoint (the others are
**   stored elsewhere in the database).
................................................................................
**   This option may only be used before lsm_open() is called. Invoking it
**   after lsm_open() has been called results in an LSM_MISUSE error.
**
** LSM_CONFIG_GET_COMPRESSION:
**   Query the compression methods used to compress and decompress database
**   content.
*/
#define LSM_CONFIG_AUTOFLUSH           1
#define LSM_CONFIG_PAGE_SIZE           2
#define LSM_CONFIG_SAFETY              3
#define LSM_CONFIG_BLOCK_SIZE          4
#define LSM_CONFIG_AUTOWORK            5
#define LSM_CONFIG_LOG_SIZE            6
#define LSM_CONFIG_MMAP                7
#define LSM_CONFIG_USE_LOG             8
#define LSM_CONFIG_AUTOMERGE           9
#define LSM_CONFIG_MAX_FREELIST       10
#define LSM_CONFIG_MULTIPLE_PROCESSES 11
#define LSM_CONFIG_AUTOCHECKPOINT     12
#define LSM_CONFIG_SET_COMPRESSION    13
#define LSM_CONFIG_GET_COMPRESSION    14

#define LSM_SAFETY_OFF    0
................................................................................
**   to is populated with a pointer to a nul-terminated string containing
**   the string representation of a Tcl data-structure. The returned 
**   string should be eventually freed by the caller using lsm_free().
**
**   The Tcl structure returned is a list containing one element for each
**   free block in the database. The element itself consists of two 
**   integers - the block number and the id of the snapshot that freed it.
**
** LSM_INFO_CHECKPOINT_SIZE:
**   The third argument should be of type (int *). The location pointed to
**   by this argument is populated with the number of bytes written to the
**   database file since the most recent checkpoint.
**
** LSM_INFO_TREE_SIZE:
**   If this value is passed as the second argument to an lsm_info() call, it
**   should be followed by two arguments of type (int *) (for a total of four
**   arguments).
**
**   At any time, there are either one or two tree structures held in shared
**   memory that new database clients will access (there may also be additional
**   tree structures being used by older clients - this API does not provide
**   information on them). One tree structure - the current tree - is used to
**   accumulate new data written to the database. The other tree structure -
**   the old tree - is a read-only tree holding older data and may be flushed 
**   to disk at any time.
** 
**   Assuming no error occurs, the location pointed to by the first of the two
**   (int *) arguments is set to the size of the old in-memory tree in bytes.
**   The second is set to the size of the current, or live in-memory tree.
*/
#define LSM_INFO_NWRITE           1
#define LSM_INFO_NREAD            2
#define LSM_INFO_DB_STRUCTURE     3
#define LSM_INFO_LOG_STRUCTURE    4
#define LSM_INFO_ARRAY_STRUCTURE  5
#define LSM_INFO_PAGE_ASCII_DUMP  6
#define LSM_INFO_PAGE_HEX_DUMP    7
#define LSM_INFO_FREELIST         8
#define LSM_INFO_ARRAY_PAGES      9
#define LSM_INFO_CHECKPOINT_SIZE 10
#define LSM_INFO_TREE_SIZE       11


/* 
** CAPI: Opening and Closing Write Transactions
**
** These functions are used to open and close transactions and nested 
** sub-transactions.
................................................................................
** error code if an error occurs or LSM_OK otherwise.
**
** If the current snapshot has already been checkpointed, calling this 
** function is a no-op. In this case if pnByte is not NULL, *pnByte is
** set to 0. Or, if the current snapshot is successfully checkpointed
** by this function and pbCkpt is not NULL, *pnByte is set to the number
** of bytes written to the database file since the previous checkpoint
** (the same measure as returned by the LSM_INFO_CHECKPOINT_SIZE query).
*/
int lsm_checkpoint(lsm_db *pDb, int *pnByte);

/*
** CAPI: Opening and Closing Database Cursors
**
** Open and close a database cursor.
................................................................................
void lsm_config_log(lsm_db *, void (*)(void *, int, const char *), void *);

/*
** Configure a callback that is invoked if the database connection ever
** writes to the database file.
*/
void lsm_config_work_hook(lsm_db *, void (*)(lsm_db *, void *), void *);







































/* ENDOFAPI */
#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif /* ifndef _LSM_H */

Changes to src/lsmInt.h

38
39
40
41
42
43
44
45
46
47
48

49
50




51
52
53
54
55
56
57
...
233
234
235
236
237
238
239

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
...
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
...
537
538
539
540
541
542
543

544
545
546
547
548
549
550
# endif
#endif

/*
** Default values for various data structure parameters. These may be
** overridden by calls to lsm_config().
*/
#define LSM_DFLT_PAGE_SIZE       (4 * 1024)
#define LSM_DFLT_BLOCK_SIZE      (2 * 1024 * 1024)
#define LSM_DFLT_WRITE_BUFFER    (2 * 1024 * 1024)
#define LSM_DFLT_AUTOCHECKPOINT  (4 * 1024 * 1024)

#define LSM_DFLT_LOG_SIZE        (128*1024)
#define LSM_DFLT_NMERGE          4





/* Initial values for log file checksums. These are only used if the 
** database file does not contain a valid checkpoint.  */
#define LSM_CKSUM0_INIT 42
#define LSM_CKSUM1_INIT 42

#define LSM_META_PAGE_SIZE 4096
................................................................................
  i64 iSnapshotId;                /* Log space has been reclaimed to this ss */
  LogRegion aRegion[3];           /* Log file regions (see docs in lsm_log.c) */
};

struct TreeRoot {
  u32 iRoot;
  u32 nHeight;

  u32 iTransId;
};

/*
** Tree header structure. 
*/
struct TreeHeader {
  u32 iUsedShmid;                 /* Id of first shm chunk used by this tree */
  u32 iNextShmid;                 /* Shm-id of next chunk allocated */
  u32 iFirst;                     /* Chunk number of smallest shm-id */
  u32 nChunk;                     /* Number of chunks in shared-memory file */
  TreeRoot root;                  /* Root and height of current tree */
  u32 iWrite;                     /* Write offset in shm file */
  u32 nByte;                      /* Size of current tree structure in bytes */
  TreeRoot oldroot;               /* Root and height of the previous tree */
  u32 iOldShmid;                  /* Last shm-id used by previous tree */
  i64 iOldLog;                    /* Log offset associated with old tree */
  u32 oldcksum0;
  u32 oldcksum1;
  DbLog log;                      /* Current layout of log file */ 
  u32 aCksum[2];                  /* Checksums 1 and 2. */
................................................................................
  /* Database handle configuration */
  lsm_env *pEnv;                            /* runtime environment */
  int (*xCmp)(void *, int, void *, int);    /* Compare function */

  /* Values configured by calls to lsm_config */
  int eSafety;                    /* LSM_SAFETY_OFF, NORMAL or FULL */
  int bAutowork;                  /* Configured by LSM_CONFIG_AUTOWORK */
  int nTreeLimit;                 /* Configured by LSM_CONFIG_WRITE_BUFFER */
  int nMerge;                     /* Configured by LSM_CONFIG_NMERGE */
  int nLogSz;                     /* Configured by LSM_CONFIG_LOG_SIZE */
  int bUseLog;                    /* Configured by LSM_CONFIG_USE_LOG */
  int nDfltPgsz;                  /* Configured by LSM_CONFIG_PAGE_SIZE */
  int nDfltBlksz;                 /* Configured by LSM_CONFIG_BLOCK_SIZE */
  int nMaxFreelist;               /* Configured by LSM_CONFIG_MAX_FREELIST */
  int bMmap;                      /* Configured by LSM_CONFIG_MMAP */
  int nAutockpt;                  /* Configured by LSM_CONFIG_AUTOCHECKPOINT */
................................................................................
void lsmCheckpointLogoffset(u32 *aCkpt, DbLog *pLog);
void lsmCheckpointZeroLogoffset(lsm_db *);

int lsmCheckpointSaveWorker(lsm_db *pDb, int);
int lsmDatabaseFull(lsm_db *pDb);
int lsmCheckpointSynced(lsm_db *pDb, i64 *piId, i64 *piLog, u32 *pnWrite);



/* 
** Functions from file "lsm_tree.c".
*/
int lsmTreeNew(lsm_env *, int (*)(void *, int, void *, int), Tree **ppTree);
void lsmTreeRelease(lsm_env *, Tree *);
int lsmTreeInit(lsm_db *);







|
|
|
|
>
|
|
>
>
>
>







 







>













<







 







|
|







 







>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258

259
260
261
262
263
264
265
...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
...
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
# endif
#endif

/*
** Default values for various data structure parameters. These may be
** overridden by calls to lsm_config().
*/
#define LSM_DFLT_PAGE_SIZE          (4 * 1024)
#define LSM_DFLT_BLOCK_SIZE         (1 * 1024 * 1024)
#define LSM_DFLT_AUTOFLUSH          (1 * 1024 * 1024)
#define LSM_DFLT_AUTOCHECKPOINT     (2 * 1024 * 1024)
#define LSM_DFLT_AUTOWORK           1
#define LSM_DFLT_LOG_SIZE           (128*1024)
#define LSM_DFLT_AUTOMERGE          4
#define LSM_DFLT_SAFETY             LSM_SAFETY_NORMAL
#define LSM_DFLT_MMAP               LSM_IS_64_BIT
#define LSM_DFLT_MULTIPLE_PROCESSES 1
#define LSM_DFLT_USE_LOG            1

/* Initial values for log file checksums. These are only used if the 
** database file does not contain a valid checkpoint.  */
#define LSM_CKSUM0_INIT 42
#define LSM_CKSUM1_INIT 42

#define LSM_META_PAGE_SIZE 4096
................................................................................
  i64 iSnapshotId;                /* Log space has been reclaimed to this ss */
  LogRegion aRegion[3];           /* Log file regions (see docs in lsm_log.c) */
};

struct TreeRoot {
  u32 iRoot;
  u32 nHeight;
  u32 nByte;                      /* Total size of this tree in bytes */
  u32 iTransId;
};

/*
** Tree header structure. 
*/
struct TreeHeader {
  u32 iUsedShmid;                 /* Id of first shm chunk used by this tree */
  u32 iNextShmid;                 /* Shm-id of next chunk allocated */
  u32 iFirst;                     /* Chunk number of smallest shm-id */
  u32 nChunk;                     /* Number of chunks in shared-memory file */
  TreeRoot root;                  /* Root and height of current tree */
  u32 iWrite;                     /* Write offset in shm file */

  TreeRoot oldroot;               /* Root and height of the previous tree */
  u32 iOldShmid;                  /* Last shm-id used by previous tree */
  i64 iOldLog;                    /* Log offset associated with old tree */
  u32 oldcksum0;
  u32 oldcksum1;
  DbLog log;                      /* Current layout of log file */ 
  u32 aCksum[2];                  /* Checksums 1 and 2. */
................................................................................
  /* Database handle configuration */
  lsm_env *pEnv;                            /* runtime environment */
  int (*xCmp)(void *, int, void *, int);    /* Compare function */

  /* Values configured by calls to lsm_config */
  int eSafety;                    /* LSM_SAFETY_OFF, NORMAL or FULL */
  int bAutowork;                  /* Configured by LSM_CONFIG_AUTOWORK */
  int nTreeLimit;                 /* Configured by LSM_CONFIG_AUTOFLUSH */
  int nMerge;                     /* Configured by LSM_CONFIG_AUTOMERGE */
  int nLogSz;                     /* Configured by LSM_CONFIG_LOG_SIZE */
  int bUseLog;                    /* Configured by LSM_CONFIG_USE_LOG */
  int nDfltPgsz;                  /* Configured by LSM_CONFIG_PAGE_SIZE */
  int nDfltBlksz;                 /* Configured by LSM_CONFIG_BLOCK_SIZE */
  int nMaxFreelist;               /* Configured by LSM_CONFIG_MAX_FREELIST */
  int bMmap;                      /* Configured by LSM_CONFIG_MMAP */
  int nAutockpt;                  /* Configured by LSM_CONFIG_AUTOCHECKPOINT */
................................................................................
void lsmCheckpointLogoffset(u32 *aCkpt, DbLog *pLog);
void lsmCheckpointZeroLogoffset(lsm_db *);

int lsmCheckpointSaveWorker(lsm_db *pDb, int);
int lsmDatabaseFull(lsm_db *pDb);
int lsmCheckpointSynced(lsm_db *pDb, i64 *piId, i64 *piLog, u32 *pnWrite);

int lsmCheckpointSize(lsm_db *db, int *pnByte);

/* 
** Functions from file "lsm_tree.c".
*/
int lsmTreeNew(lsm_env *, int (*)(void *, int, void *, int), Tree **ppTree);
void lsmTreeRelease(lsm_env *, Tree *);
int lsmTreeInit(lsm_db *);

Changes to src/lsm_ckpt.c

1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
      &pDb->aSnapshot[nCkpt-2], &pDb->aSnapshot[nCkpt-1]
  );

  memcpy(pDb->pShmhdr->aSnap1, pDb->aSnapshot, nCkpt*sizeof(u32));
  memcpy(pDb->pShmhdr->aSnap2, pDb->aSnapshot, nCkpt*sizeof(u32));
}

int lsm_ckpt_size(lsm_db *db, int *pnByte){
  ShmHeader *pShm = db->pShmhdr;
  int rc = LSM_OK;
  u32 nSynced;

  rc = lsmCheckpointSynced(db, 0, 0, &nSynced);
  if( rc==LSM_OK ){
    u32 nPgsz = db->pShmhdr->aSnap1[CKPT_HDR_PGSZ];







|







1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
      &pDb->aSnapshot[nCkpt-2], &pDb->aSnapshot[nCkpt-1]
  );

  memcpy(pDb->pShmhdr->aSnap1, pDb->aSnapshot, nCkpt*sizeof(u32));
  memcpy(pDb->pShmhdr->aSnap2, pDb->aSnapshot, nCkpt*sizeof(u32));
}

int lsmCheckpointSize(lsm_db *db, int *pnByte){
  ShmHeader *pShm = db->pShmhdr;
  int rc = LSM_OK;
  u32 nSynced;

  rc = lsmCheckpointSynced(db, 0, 0, &nSynced);
  if( rc==LSM_OK ){
    u32 nPgsz = db->pShmhdr->aSnap1[CKPT_HDR_PGSZ];

Changes to src/lsm_main.c

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
...
444
445
446
447
448
449
450





































451
452
453
454
455
456
457
...
502
503
504
505
506
507
508













509
510
511
512
513
514
515
...
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834

  /* Allocate the new database handle */
  *ppDb = pDb = (lsm_db *)lsmMallocZero(pEnv, sizeof(lsm_db));
  if( pDb==0 ) return LSM_NOMEM_BKPT;

  /* Initialize the new object */
  pDb->pEnv = pEnv;
  pDb->nTreeLimit = LSM_DFLT_WRITE_BUFFER;
  pDb->nAutockpt = LSM_DFLT_AUTOCHECKPOINT;
  pDb->bAutowork = 1;
  pDb->eSafety = LSM_SAFETY_NORMAL;
  pDb->xCmp = xCmp;
  pDb->nLogSz = LSM_DFLT_LOG_SIZE;
  pDb->nDfltPgsz = LSM_DFLT_PAGE_SIZE;
  pDb->nDfltBlksz = LSM_DFLT_BLOCK_SIZE;
  pDb->nMerge = LSM_DFLT_NMERGE;
  pDb->nMaxFreelist = LSM_MAX_FREELIST_ENTRIES;
  pDb->bUseLog = 1;
  pDb->iReader = -1;
  pDb->bMultiProc = 1;
  pDb->bMmap = LSM_IS_64_BIT;
  pDb->xLog = xLog;
  return LSM_OK;
}

lsm_env *lsm_get_env(lsm_db *pDb){
  assert( pDb->pEnv );
  return pDb->pEnv;
................................................................................

int lsm_config(lsm_db *pDb, int eParam, ...){
  int rc = LSM_OK;
  va_list ap;
  va_start(ap, eParam);

  switch( eParam ){
    case LSM_CONFIG_WRITE_BUFFER: {
      int *piVal = va_arg(ap, int *);
      if( *piVal>=0 ){
        pDb->nTreeLimit = *piVal;
      }
      *piVal = pDb->nTreeLimit;
      break;
    }
................................................................................
      if( pDb->nTransOpen==0 && (*piVal==0 || *piVal==1) ){
        pDb->bUseLog = *piVal;
      }
      *piVal = pDb->bUseLog;
      break;
    }

    case LSM_CONFIG_NMERGE: {
      int *piVal = va_arg(ap, int *);
      if( *piVal>1 ) pDb->nMerge = *piVal;
      *piVal = pDb->nMerge;
      break;
    }

    case LSM_CONFIG_MAX_FREELIST: {
................................................................................
    *pzOut = s.z;
  }

  /* Release the snapshot and return */
  infoFreeWorker(pDb, bUnlock);
  return rc;
}






































int lsm_info(lsm_db *pDb, int eParam, ...){
  int rc = LSM_OK;
  va_list ap;
  va_start(ap, eParam);

  switch( eParam ){
................................................................................
    }

    case LSM_INFO_FREELIST: {
      char **pzVal = va_arg(ap, char **);
      rc = lsmInfoFreelist(pDb, pzVal);
      break;
    }














    default:
      rc = LSM_MISUSE;
      break;
  }

  va_end(ap);
................................................................................
    }
    dbReleaseClientSnapshot(pDb);
  }

  return rc;
}

int lsm_tree_size(lsm_db *db, int *pnOld, int *pnNew){
  ShmHeader *pShm = db->pShmhdr;

  *pnNew = (int)pShm->hdr1.nByte;
  *pnOld = 0;
  if( pShm->hdr1.iOldShmid ){
    i64 iOff = pShm->hdr1.iOldLog;
    if( iOff!=lsmCheckpointLogOffset(pShm->aSnap1) ){
      *pnOld = 1;
    }
  }

  return LSM_OK;
}









|

|
|




|

|

|
|







 







|







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
...
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
...
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
...
862
863
864
865
866
867
868


869














  /* Allocate the new database handle */
  *ppDb = pDb = (lsm_db *)lsmMallocZero(pEnv, sizeof(lsm_db));
  if( pDb==0 ) return LSM_NOMEM_BKPT;

  /* Initialize the new object */
  pDb->pEnv = pEnv;
  pDb->nTreeLimit = LSM_DFLT_AUTOFLUSH;
  pDb->nAutockpt = LSM_DFLT_AUTOCHECKPOINT;
  pDb->bAutowork = LSM_DFLT_AUTOWORK;
  pDb->eSafety = LSM_DFLT_SAFETY;
  pDb->xCmp = xCmp;
  pDb->nLogSz = LSM_DFLT_LOG_SIZE;
  pDb->nDfltPgsz = LSM_DFLT_PAGE_SIZE;
  pDb->nDfltBlksz = LSM_DFLT_BLOCK_SIZE;
  pDb->nMerge = LSM_DFLT_AUTOMERGE;
  pDb->nMaxFreelist = LSM_MAX_FREELIST_ENTRIES;
  pDb->bUseLog = LSM_DFLT_USE_LOG;
  pDb->iReader = -1;
  pDb->bMultiProc = LSM_DFLT_MULTIPLE_PROCESSES;
  pDb->bMmap = LSM_DFLT_MMAP;
  pDb->xLog = xLog;
  return LSM_OK;
}

lsm_env *lsm_get_env(lsm_db *pDb){
  assert( pDb->pEnv );
  return pDb->pEnv;
................................................................................

int lsm_config(lsm_db *pDb, int eParam, ...){
  int rc = LSM_OK;
  va_list ap;
  va_start(ap, eParam);

  switch( eParam ){
    case LSM_CONFIG_AUTOFLUSH: {
      int *piVal = va_arg(ap, int *);
      if( *piVal>=0 ){
        pDb->nTreeLimit = *piVal;
      }
      *piVal = pDb->nTreeLimit;
      break;
    }
................................................................................
      if( pDb->nTransOpen==0 && (*piVal==0 || *piVal==1) ){
        pDb->bUseLog = *piVal;
      }
      *piVal = pDb->bUseLog;
      break;
    }

    case LSM_CONFIG_AUTOMERGE: {
      int *piVal = va_arg(ap, int *);
      if( *piVal>1 ) pDb->nMerge = *piVal;
      *piVal = pDb->nMerge;
      break;
    }

    case LSM_CONFIG_MAX_FREELIST: {
................................................................................
    *pzOut = s.z;
  }

  /* Release the snapshot and return */
  infoFreeWorker(pDb, bUnlock);
  return rc;
}

static int infoTreeSize(lsm_db *db, int *pnOld, int *pnNew){
  ShmHeader *pShm = db->pShmhdr;
  TreeHeader *p = &pShm->hdr1;

  /* The following code suffers from two race conditions, as it accesses and
  ** trusts the contents of shared memory without verifying checksums:
  **
  **   * The two values read - TreeHeader.root.nByte and oldroot.nByte - are 
  **     32-bit fields. It is assumed that reading from one of these
  **     is atomic - that it is not possible to read a partially written
  **     garbage value. However the two values may be mutually inconsistent. 
  **
  **   * TreeHeader.iLogOff is a 64-bit value. And lsmCheckpointLogOffset()
  **     reads a 64-bit value from a snapshot stored in shared memory. It
  **     is assumed that in each case it is possible to read a partially
  **     written garbage value. If this occurs, then the value returned
  **     for the size of the "old" tree may reflect the size of an "old"
  **     tree that was recently flushed to disk.
  **
  ** Given the context in which this function is called (as a result of an
  ** lsm_info(LSM_INFO_TREE_SIZE) request), neither of these are considered to
  ** be problems.
  */
  *pnNew = (int)p->root.nByte;
  if( p->iOldShmid ){
    if( p->iLogOff==lsmCheckpointLogOffset(pShm->aSnap1) ){
      *pnOld = 0;
    }else{
      *pnOld = (int)p->oldroot.nByte;
    }
  }else{
    *pnOld = 0;
  }

  return LSM_OK;
}

int lsm_info(lsm_db *pDb, int eParam, ...){
  int rc = LSM_OK;
  va_list ap;
  va_start(ap, eParam);

  switch( eParam ){
................................................................................
    }

    case LSM_INFO_FREELIST: {
      char **pzVal = va_arg(ap, char **);
      rc = lsmInfoFreelist(pDb, pzVal);
      break;
    }

    case LSM_INFO_CHECKPOINT_SIZE: {
      int *pnByte = va_arg(ap, int *);
      rc = lsmCheckpointSize(pDb, pnByte);
      break;
    }

    case LSM_INFO_TREE_SIZE: {
      int *pnOld = va_arg(ap, int *);
      int *pnNew = va_arg(ap, int *);
      rc = infoTreeSize(pDb, pnOld, pnNew);
      break;
    }

    default:
      rc = LSM_MISUSE;
      break;
  }

  va_end(ap);
................................................................................
    }
    dbReleaseClientSnapshot(pDb);
  }

  return rc;
}

















Changes to src/lsm_tree.c

684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
....
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
....
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
      /* Advance to the next chunk */
      iWrite = iNext * CHUNK_SIZE + CHUNK_HDR;
    }

    /* Allocate space at iWrite. */
    iRet = iWrite;
    pDb->treehdr.iWrite = iWrite + nByte;
    pDb->treehdr.nByte += nByte;
  }
  return iRet;
}

/*
** Allocate and zero nByte bytes of space within the *-shm file.
*/
................................................................................
    pDb->treehdr.oldcksum1 = pDb->treehdr.log.cksum1;
    pDb->treehdr.iOldShmid = pDb->treehdr.iNextShmid-1;
    memcpy(&pDb->treehdr.oldroot, &pDb->treehdr.root, sizeof(TreeRoot));

    pDb->treehdr.root.iTransId = 1;
    pDb->treehdr.root.iRoot = 0;
    pDb->treehdr.root.nHeight = 0;
    pDb->treehdr.nByte = 0;
  }
}

void lsmTreeDiscardOld(lsm_db *pDb){
  assert( lsmShmAssertLock(pDb, LSM_LOCK_WRITER, LSM_LOCK_EXCL) 
       || lsmShmAssertLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_EXCL) 
  );
................................................................................
}

/*
** Return, in bytes, the amount of memory currently used by the tree 
** structure.
*/
int lsmTreeSize(lsm_db *pDb){
  return pDb->treehdr.nByte;
}

/*
** Open a cursor on the in-memory tree pTree.
*/
int lsmTreeCursorNew(lsm_db *pDb, int bOld, TreeCursor **ppCsr){
  TreeCursor *pCsr;







|







 







|







 







|







684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
....
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
....
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
      /* Advance to the next chunk */
      iWrite = iNext * CHUNK_SIZE + CHUNK_HDR;
    }

    /* Allocate space at iWrite. */
    iRet = iWrite;
    pDb->treehdr.iWrite = iWrite + nByte;
    pDb->treehdr.root.nByte += nByte;
  }
  return iRet;
}

/*
** Allocate and zero nByte bytes of space within the *-shm file.
*/
................................................................................
    pDb->treehdr.oldcksum1 = pDb->treehdr.log.cksum1;
    pDb->treehdr.iOldShmid = pDb->treehdr.iNextShmid-1;
    memcpy(&pDb->treehdr.oldroot, &pDb->treehdr.root, sizeof(TreeRoot));

    pDb->treehdr.root.iTransId = 1;
    pDb->treehdr.root.iRoot = 0;
    pDb->treehdr.root.nHeight = 0;
    pDb->treehdr.root.nByte = 0;
  }
}

void lsmTreeDiscardOld(lsm_db *pDb){
  assert( lsmShmAssertLock(pDb, LSM_LOCK_WRITER, LSM_LOCK_EXCL) 
       || lsmShmAssertLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_EXCL) 
  );
................................................................................
}

/*
** Return, in bytes, the amount of memory currently used by the tree 
** structure.
*/
int lsmTreeSize(lsm_db *pDb){
  return pDb->treehdr.root.nByte;
}

/*
** Open a cursor on the in-memory tree pTree.
*/
int lsmTreeCursorNew(lsm_db *pDb, int bOld, TreeCursor **ppCsr){
  TreeCursor *pCsr;

Changes to test/csr1.test

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# tree to be flushed to disk, 
#
populate_db_2
do_execsql_test 3.1 {
  BEGIN;
    INSERT INTO t1 VALUES(10, randstr(910, 910));
}
do_test 3.2 { sqlite4_lsm_config db main write-buffer } [expr 2*1024*1024]
do_test 3.3 { sqlite4_lsm_config db main write-buffer 4096 } 4096

do_test 3.4 {
  set res [list]
  db eval { SELECT a, length(b) AS l FROM t1 } {
    lappend res $a $l
    # The following commit will flush the in-memory tree to disk.
    if {$a == 5} { db eval COMMIT }







|
|







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# tree to be flushed to disk, 
#
populate_db_2
do_execsql_test 3.1 {
  BEGIN;
    INSERT INTO t1 VALUES(10, randstr(910, 910));
}
do_test 3.2 { sqlite4_lsm_config db main autoflush } [expr 2*1024*1024]
do_test 3.3 { sqlite4_lsm_config db main autoflush 4096 } 4096

do_test 3.4 {
  set res [list]
  db eval { SELECT a, length(b) AS l FROM t1 } {
    lappend res $a $l
    # The following commit will flush the in-memory tree to disk.
    if {$a == 5} { db eval COMMIT }

Changes to test/lsm1.test

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
set testprefix lsm1
db close


proc reopen {{bClear 0}} {
  catch {db close}
  if {$bClear} { forcedelete test.db }
  lsm_open db test.db {mmap 0 nmerge 2 autowork 0}
}

proc contents {} {
  db csr_open csr
  set res [list]
  for {csr first} {[csr valid]} {csr next} {
    lappend res [list [csr key] [csr value]]
................................................................................
  db work 10

  contents
} {{10 ten} {40 forty}}

do_test 5.2 {
  reopen 1
  db config {nmerge 4}

  dbwrite { 10 ten    }  ; db flush
  dbwrite { 20 twenty }  ; db flush
  dbwrite { 30 thirty }  ; db flush
  dbwrite { 40 forty  }  ; db flush
  db work 10

  db delete_range 10 17  ; db flush
  dbwrite {17 seventeen} ; db flush
  db delete_range 10 17  ; db flush

  db config {nmerge 3}
  db work 10

  contents
} {{10 ten} {17 seventeen} {20 twenty} {30 thirty} {40 forty}}

do_test 5.3 {
  reopen 1
  db config {nmerge 4}

  dbwrite { 10 ten    }  ; db flush
  dbwrite { 20 twenty }  ; db flush
  dbwrite { 30 thirty }  ; db flush
  dbwrite { 40 forty  }  ; db flush
  db work 10

  db delete_range 10 17  ; db flush
  db delete_range 12 19  ; db flush
  dbwrite {17 seventeen} ; db flush

  db config {nmerge 3}
  db work 10

  contents
} {{10 ten} {17 seventeen} {20 twenty} {30 thirty} {40 forty}}

finish_test







|







 







|











|







|











|






14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
set testprefix lsm1
db close


proc reopen {{bClear 0}} {
  catch {db close}
  if {$bClear} { forcedelete test.db }
  lsm_open db test.db {mmap 0 automerge 2 autowork 0}
}

proc contents {} {
  db csr_open csr
  set res [list]
  for {csr first} {[csr valid]} {csr next} {
    lappend res [list [csr key] [csr value]]
................................................................................
  db work 10

  contents
} {{10 ten} {40 forty}}

do_test 5.2 {
  reopen 1
  db config {automerge 4}

  dbwrite { 10 ten    }  ; db flush
  dbwrite { 20 twenty }  ; db flush
  dbwrite { 30 thirty }  ; db flush
  dbwrite { 40 forty  }  ; db flush
  db work 10

  db delete_range 10 17  ; db flush
  dbwrite {17 seventeen} ; db flush
  db delete_range 10 17  ; db flush

  db config {automerge 3}
  db work 10

  contents
} {{10 ten} {17 seventeen} {20 twenty} {30 thirty} {40 forty}}

do_test 5.3 {
  reopen 1
  db config {automerge 4}

  dbwrite { 10 ten    }  ; db flush
  dbwrite { 20 twenty }  ; db flush
  dbwrite { 30 thirty }  ; db flush
  dbwrite { 40 forty  }  ; db flush
  db work 10

  db delete_range 10 17  ; db flush
  db delete_range 12 19  ; db flush
  dbwrite {17 seventeen} ; db flush

  db config {automerge 3}
  db work 10

  contents
} {{10 ten} {17 seventeen} {20 twenty} {30 thirty} {40 forty}}

finish_test

Changes to test/test_lsm.c

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
...
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
){
  struct Switch {
    const char *zSwitch;
    int iVal;
  } aParam[] = {
    { "log-size",       LSM_CONFIG_LOG_SIZE }, 
    { "safety",         LSM_CONFIG_SAFETY }, 
    { "write-buffer",   LSM_CONFIG_WRITE_BUFFER }, 
    { "mmap",           LSM_CONFIG_MMAP }, 
    { "page-size",      LSM_CONFIG_PAGE_SIZE }, 
    { "autowork",       LSM_CONFIG_AUTOWORK }, 
    { 0, 0 }
  };

  const char *zDb;                /* objv[1] as a string */
................................................................................
  rc = getDbPointer(interp, zDb, &db);
  if( rc!=TCL_OK ) return rc;

  rc = sqlite4_kvstore_control(db, zName, SQLITE4_KVCTRL_LSM_HANDLE, &pLsm);
  if( rc==SQLITE4_OK ){
    int nZero = 0;
    int nOrig = -1;
    lsm_config(pLsm, LSM_CONFIG_WRITE_BUFFER, &nOrig);
    lsm_config(pLsm, LSM_CONFIG_WRITE_BUFFER, &nZero);
    rc = lsm_begin(pLsm, 1);
    if( rc==LSM_OK ) rc = lsm_commit(pLsm, 0);
    lsm_config(pLsm, LSM_CONFIG_WRITE_BUFFER, &nOrig);
  }
  if( rc!=SQLITE4_OK ){
    Tcl_SetResult(interp, (char *)sqlite4TestErrorName(rc), TCL_STATIC);
    return TCL_ERROR;
  }

  Tcl_ResetResult(interp);
................................................................................
}

static int testConfigureLsm(Tcl_Interp *interp, lsm_db *db, Tcl_Obj *pObj){
  struct Lsmconfig {
    const char *zOpt;
    int eOpt;
  } aConfig[] = {
    { "write_buffer",     LSM_CONFIG_WRITE_BUFFER },
    { "page_size",        LSM_CONFIG_PAGE_SIZE },
    { "block_size",       LSM_CONFIG_BLOCK_SIZE },
    { "safety",           LSM_CONFIG_SAFETY },
    { "autowork",         LSM_CONFIG_AUTOWORK },
    { "autocheckpoint",   LSM_CONFIG_AUTOCHECKPOINT },
    { "log_size",         LSM_CONFIG_LOG_SIZE },
    { "mmap",             LSM_CONFIG_MMAP },
    { "use_log",          LSM_CONFIG_USE_LOG },
    { "nmerge",           LSM_CONFIG_NMERGE },
    { "max_freelist",     LSM_CONFIG_MAX_FREELIST },
    { "multi_proc",       LSM_CONFIG_MULTIPLE_PROCESSES },
    { 0, 0 }
  };
  int nElem;
  int i;
  Tcl_Obj **apElem;







|







 







|
|


|







 







|








|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
...
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
){
  struct Switch {
    const char *zSwitch;
    int iVal;
  } aParam[] = {
    { "log-size",       LSM_CONFIG_LOG_SIZE }, 
    { "safety",         LSM_CONFIG_SAFETY }, 
    { "autoflush",      LSM_CONFIG_AUTOFLUSH }, 
    { "mmap",           LSM_CONFIG_MMAP }, 
    { "page-size",      LSM_CONFIG_PAGE_SIZE }, 
    { "autowork",       LSM_CONFIG_AUTOWORK }, 
    { 0, 0 }
  };

  const char *zDb;                /* objv[1] as a string */
................................................................................
  rc = getDbPointer(interp, zDb, &db);
  if( rc!=TCL_OK ) return rc;

  rc = sqlite4_kvstore_control(db, zName, SQLITE4_KVCTRL_LSM_HANDLE, &pLsm);
  if( rc==SQLITE4_OK ){
    int nZero = 0;
    int nOrig = -1;
    lsm_config(pLsm, LSM_CONFIG_AUTOFLUSH, &nOrig);
    lsm_config(pLsm, LSM_CONFIG_AUTOFLUSH, &nZero);
    rc = lsm_begin(pLsm, 1);
    if( rc==LSM_OK ) rc = lsm_commit(pLsm, 0);
    lsm_config(pLsm, LSM_CONFIG_AUTOFLUSH, &nOrig);
  }
  if( rc!=SQLITE4_OK ){
    Tcl_SetResult(interp, (char *)sqlite4TestErrorName(rc), TCL_STATIC);
    return TCL_ERROR;
  }

  Tcl_ResetResult(interp);
................................................................................
}

static int testConfigureLsm(Tcl_Interp *interp, lsm_db *db, Tcl_Obj *pObj){
  struct Lsmconfig {
    const char *zOpt;
    int eOpt;
  } aConfig[] = {
    { "autoflush",        LSM_CONFIG_AUTOFLUSH },
    { "page_size",        LSM_CONFIG_PAGE_SIZE },
    { "block_size",       LSM_CONFIG_BLOCK_SIZE },
    { "safety",           LSM_CONFIG_SAFETY },
    { "autowork",         LSM_CONFIG_AUTOWORK },
    { "autocheckpoint",   LSM_CONFIG_AUTOCHECKPOINT },
    { "log_size",         LSM_CONFIG_LOG_SIZE },
    { "mmap",             LSM_CONFIG_MMAP },
    { "use_log",          LSM_CONFIG_USE_LOG },
    { "automerge",        LSM_CONFIG_AUTOMERGE },
    { "max_freelist",     LSM_CONFIG_MAX_FREELIST },
    { "multi_proc",       LSM_CONFIG_MULTIPLE_PROCESSES },
    { 0, 0 }
  };
  int nElem;
  int i;
  Tcl_Obj **apElem;

Changes to www/lsmapi.wiki

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
..
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77


78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

96
97
98
99
100
101
102

103
104
105
106
107
108
109
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289


290
291
292
293
294
295
296
...
347
348
349
350
351
352
353
















354
355
356
357
358
359
360
...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
...
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
<li><a href="#extracting" style=text-decoration:none>Extracting Data From Database Cursors</a>
<li><a href="#change" style=text-decoration:none>Change these!!</a>

</ol>
<h1 style=clear:both>All LSM API Functions</h1>
<span style=display:block;float:left;width:35ex><a href=#lsm_begin>lsm_begin</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_checkpoint>lsm_checkpoint</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_ckpt_size>lsm_ckpt_size</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_close>lsm_close</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_commit>lsm_commit</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_config>lsm_config</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_config_log>lsm_config_log</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_config_work_hook>lsm_config_work_hook</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_csr_close>lsm_csr_close</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_csr_cmp>lsm_csr_cmp</a></span>
................................................................................
<span style=display:block;float:left;width:35ex><a href=#lsm_flush>lsm_flush</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_free>lsm_free</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_info>lsm_info</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_insert>lsm_insert</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_new>lsm_new</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_open>lsm_open</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_rollback>lsm_rollback</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_tree_size>lsm_tree_size</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_work>lsm_work</a></span>
<br style=clear:both>
<h1 style=clear:both>All LSM API Types</h1>
<span style=display:block;float:left;width:35ex><a href=#lsm_compress>lsm_compress</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_env>lsm_env</a></span>
<br style=clear:both>
<h1>All LSM API Constants</h1>
<span style=display:block;float:left;width:35ex><a href=#LSM_BUSY>LSM_BUSY</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CANTOPEN>LSM_CANTOPEN</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_AUTOCHECKPOINT>LSM_CONFIG_AUTOCHECKPOINT</a></span>


<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_AUTOWORK>LSM_CONFIG_AUTOWORK</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_BLOCK_SIZE>LSM_CONFIG_BLOCK_SIZE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_GET_COMPRESSION>LSM_CONFIG_GET_COMPRESSION</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_LOG_SIZE>LSM_CONFIG_LOG_SIZE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_MAX_FREELIST>LSM_CONFIG_MAX_FREELIST</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_MMAP>LSM_CONFIG_MMAP</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_MULTIPLE_PROCESSES>LSM_CONFIG_MULTIPLE_PROCESSES</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_NMERGE>LSM_CONFIG_NMERGE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_PAGE_SIZE>LSM_CONFIG_PAGE_SIZE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_SAFETY>LSM_CONFIG_SAFETY</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_SET_COMPRESSION>LSM_CONFIG_SET_COMPRESSION</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_USE_LOG>LSM_CONFIG_USE_LOG</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_WRITE_BUFFER>LSM_CONFIG_WRITE_BUFFER</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CORRUPT>LSM_CORRUPT</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_ERROR>LSM_ERROR</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_FULL>LSM_FULL</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_ARRAY_PAGES>LSM_INFO_ARRAY_PAGES</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_ARRAY_STRUCTURE>LSM_INFO_ARRAY_STRUCTURE</a></span>

<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_DB_STRUCTURE>LSM_INFO_DB_STRUCTURE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_FREELIST>LSM_INFO_FREELIST</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_LOG_STRUCTURE>LSM_INFO_LOG_STRUCTURE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_NREAD>LSM_INFO_NREAD</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_NWRITE>LSM_INFO_NWRITE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_PAGE_ASCII_DUMP>LSM_INFO_PAGE_ASCII_DUMP</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_PAGE_HEX_DUMP>LSM_INFO_PAGE_HEX_DUMP</a></span>

<span style=display:block;float:left;width:35ex><a href=#LSM_IOERR>LSM_IOERR</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_MISUSE>LSM_MISUSE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_MUTEX_GLOBAL>LSM_MUTEX_GLOBAL</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_MUTEX_HEAP>LSM_MUTEX_HEAP</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_NOMEM>LSM_NOMEM</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_OK>LSM_OK</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_PROTOCOL>LSM_PROTOCOL</a></span>
................................................................................
lsm_env *lsm_default_env(void);
</verbatim>
<p>Return a pointer to the environment used by the database connection 
passed as the first argument. Assuming the argument is valid, this 
function always returns a valid environment pointer - it cannot fail.
The lsm_default_env() function returns a pointer to the default LSM
environment for the current platform.
<h2 id=configuring>Configuring a database connection.<a id=lsm_config></a><a id=LSM_CONFIG_WRITE_BUFFER></a><a id=LSM_CONFIG_PAGE_SIZE></a><a id=LSM_CONFIG_SAFETY></a><a id=LSM_CONFIG_BLOCK_SIZE></a><a id=LSM_CONFIG_AUTOWORK></a><a id=LSM_CONFIG_LOG_SIZE></a><a id=LSM_CONFIG_MMAP></a><a id=LSM_CONFIG_USE_LOG></a><a id=LSM_CONFIG_NMERGE></a><a id=LSM_CONFIG_MAX_FREELIST></a><a id=LSM_CONFIG_MULTIPLE_PROCESSES></a><a id=LSM_CONFIG_AUTOCHECKPOINT></a><a id=LSM_CONFIG_SET_COMPRESSION></a><a id=LSM_CONFIG_GET_COMPRESSION></a><a id=LSM_SAFETY_OFF></a><a id=LSM_SAFETY_NORMAL></a><a id=LSM_SAFETY_FULL></a></h2>
<verbatim>int lsm_config(lsm_db *, int, ...);
#define LSM_CONFIG_WRITE_BUFFER        1
#define LSM_CONFIG_PAGE_SIZE           2
#define LSM_CONFIG_SAFETY              3
#define LSM_CONFIG_BLOCK_SIZE          4
#define LSM_CONFIG_AUTOWORK            5
#define LSM_CONFIG_LOG_SIZE            6
#define LSM_CONFIG_MMAP                7
#define LSM_CONFIG_USE_LOG             8
#define LSM_CONFIG_NMERGE              9
#define LSM_CONFIG_MAX_FREELIST       10
#define LSM_CONFIG_MULTIPLE_PROCESSES 11
#define LSM_CONFIG_AUTOCHECKPOINT     12
#define LSM_CONFIG_SET_COMPRESSION    13
#define LSM_CONFIG_GET_COMPRESSION    14
#define LSM_SAFETY_OFF    0
#define LSM_SAFETY_NORMAL 1
#define LSM_SAFETY_FULL   2
</verbatim>
<p>The lsm_config() function is used to configure a database connection.
The following values may be passed as the second argument to lsm_config().
<p><dl><dt>LSM_CONFIG_WRITE_BUFFER<dd>A read/write integer parameter. This value determines the maximum amount
of space (in bytes) used to accumulate writes in main-memory before 
they are flushed to a level 0 segment.
<p><dt>LSM_CONFIG_PAGE_SIZE<dd>A read/write integer parameter. This parameter may only be set before
lsm_open() has been called.
<p><dt>LSM_CONFIG_BLOCK_SIZE<dd>A read/write integer parameter. This parameter may only be set before
lsm_open() has been called.
<p><dt>LSM_CONFIG_LOG_SIZE<dd>A read/write integer parameter.
................................................................................
contains all successfully committed transactions.
<p><dt>LSM_CONFIG_AUTOWORK<dd>A read/write integer parameter.
<p><dt>LSM_CONFIG_AUTOCHECKPOINT<dd>A read/write integer parameter.
<p><dt>LSM_CONFIG_MMAP<dd>A read/write integer parameter. True to use mmap() to access the 
database file. False otherwise.
<p><dt>LSM_CONFIG_USE_LOG<dd>A read/write boolean parameter. True (the default) to use the log
file normally. False otherwise.
<p><dt>LSM_CONFIG_NMERGE<dd>A read/write integer parameter. The minimum number of segments to
merge together at a time. Default value 4.
<p><dt>LSM_CONFIG_MAX_FREELIST<dd>A read/write integer parameter. The maximum number of free-list 
entries that are stored in a database checkpoint (the others are
stored elsewhere in the database).
<p>There is no reason for an application to configure or query this
parameter. It is only present because configuring a small value
makes certain parts of the lsm code easier to test.
................................................................................
<verbatim>void *lsm_malloc(lsm_env*, size_t);
void *lsm_realloc(lsm_env*, void *, size_t);
void lsm_free(lsm_env*, void *);
</verbatim>
<p>Invoke the memory allocation functions that belong to environment
pEnv. Or the system defaults if no memory allocation functions have 
been registered.
<h2 id=querying>Querying a Connection For Operational Data<a id=lsm_info></a><a id=LSM_INFO_NWRITE></a><a id=LSM_INFO_NREAD></a><a id=LSM_INFO_DB_STRUCTURE></a><a id=LSM_INFO_LOG_STRUCTURE></a><a id=LSM_INFO_ARRAY_STRUCTURE></a><a id=LSM_INFO_PAGE_ASCII_DUMP></a><a id=LSM_INFO_PAGE_HEX_DUMP></a><a id=LSM_INFO_FREELIST></a><a id=LSM_INFO_ARRAY_PAGES></a></h2>
<verbatim>int lsm_info(lsm_db *, int, ...);
#define LSM_INFO_NWRITE           1
#define LSM_INFO_NREAD            2
#define LSM_INFO_DB_STRUCTURE     3
#define LSM_INFO_LOG_STRUCTURE    4
#define LSM_INFO_ARRAY_STRUCTURE  5
#define LSM_INFO_PAGE_ASCII_DUMP  6
#define LSM_INFO_PAGE_HEX_DUMP    7
#define LSM_INFO_FREELIST         8
#define LSM_INFO_ARRAY_PAGES      9


</verbatim>
<p>Query a database connection for operational statistics or data.
The following values may be passed as the second argument to lsm_info().
<p><dl><dt>LSM_INFO_NWRITE<dd>The third parameter should be of type (int *). The location pointed
to by the third parameter is set to the number of 4KB pages written to
the database file during the lifetime of this connection. 
<p><dt>LSM_INFO_NREAD<dd>The third parameter should be of type (int *). The location pointed
................................................................................
<p><dt>LSM_INFO_FREELIST<dd>The third argument should be of type (char **). The location pointed
to is populated with a pointer to a nul-terminated string containing
the string representation of a Tcl data-structure. The returned 
string should be eventually freed by the caller using lsm_free().
<p>The Tcl structure returned is a list containing one element for each
free block in the database. The element itself consists of two 
integers - the block number and the id of the snapshot that freed it.
















</dl><h2 id=opening>Opening and Closing Write Transactions<a id=lsm_begin></a><a id=lsm_commit></a><a id=lsm_rollback></a></h2>
<verbatim>int lsm_begin(lsm_db *pDb, int iLevel);
int lsm_commit(lsm_db *pDb, int iLevel);
int lsm_rollback(lsm_db *pDb, int iLevel);
</verbatim>
<p>These functions are used to open and close transactions and nested 
sub-transactions.
................................................................................
Attempt to checkpoint the current database snapshot. Return an LSM
error code if an error occurs or LSM_OK otherwise.
<p>If the current snapshot has already been checkpointed, calling this 
function is a no-op. In this case if pnByte is not NULL, *pnByte is
set to 0. Or, if the current snapshot is successfully checkpointed
by this function and pbCkpt is not NULL, *pnByte is set to the number
of bytes written to the database file since the previous checkpoint
(the same measure as returned by lsm_ckpt_size()).
<h2 id=opening>Opening and Closing Database Cursors<a id=lsm_csr_open></a><a id=lsm_csr_close></a></h2>
<verbatim>int lsm_csr_open(lsm_db *pDb, lsm_cursor **ppCsr);
int lsm_csr_close(lsm_cursor *pCsr);
</verbatim>
<p>Open and close a database cursor.
<h2 id=positioning>Positioning Database Cursors<a id=lsm_csr_seek></a><a id=lsm_csr_first></a><a id=lsm_csr_last></a><a id=lsm_csr_next></a><a id=lsm_csr_prev></a><a id=LSM_SEEK_LEFAST></a><a id=LSM_SEEK_LE></a><a id=LSM_SEEK_EQ></a><a id=LSM_SEEK_GE></a></h2>
<verbatim>int lsm_csr_seek(lsm_cursor *pCsr, const void *pKey, int nKey, int eSeek);
................................................................................
the pKey/nKey arguments with the key that the cursor passed as the first
argument currently points to. If the cursors key is less than, equal to
or greater than pKey/nKey, *piRes is set to less than, equal to or greater
than zero before returning. LSM_OK is returned in this case.
<p>Or, if an error occurs, an LSM error code is returned and the final 
value of *piRes is undefined. If the cursor does not point to a valid
key when this function is called, LSM_MISUSE is returned.
<h2 id=change>Change these!!<a id=lsm_config_log></a><a id=lsm_config_work_hook></a><a id=lsm_tree_size></a><a id=lsm_ckpt_size></a></h2>
<verbatim>void lsm_config_log(lsm_db *, void (*)(void *, int, const char *), void *);
void lsm_config_work_hook(lsm_db *, void (*)(lsm_db *, void *), void *);
int lsm_tree_size(lsm_db *, int *pbOld, int *pnNew);
int lsm_ckpt_size(lsm_db *, int *pnByte);
</verbatim>
<p>Configure a callback to which debugging and other messages should 
be directed. Only useful for debugging lsm.
Configure a callback that is invoked if the database connection ever
writes to the database file.
The lsm_tree_size() function reports on the current state of the 
in-memory tree data structure. 
<p>At any time, there are either one or two tree structures held in shared
memory that new database clients will access (there may also be additional 
tree structures being used by older clients - this API does not provide
information on them). One tree structure - the current tree - is used to
accumulate new data written to the database. The other tree structure - the 
old tree - is a read-only tree holding older data and may be flushed to disk
at any time.
<p>If successful, this function sets *pnNew to the number of bytes of shared
memory space used by the current tree. *pbOld is set to true if the old 
tree exists, or false if it does not. 
<p>If no error occurs, LSM_OK is returned. Otherwise an LSM error code.
<p>RACE CONDITION:
<blockquote><pre>Describe the race condition this function is subject to. </blockquote></pre>
This function is used to query the amount of data that has been written
to the database file but not checkpointed (synced). If successful, *pnByte
is set to the number of bytes before returning.
<p>LSM_OK is returned if successful. Or if an error occurs, an LSM error
code is returned.
<p>RACE CONDITION:
<blockquote><pre>Describe the race condition this function is subject to. Or remove</blockquote></pre>
<blockquote><pre>it somehow.</blockquote></pre>








<







 







<










>
>







<




<





>







>







 







|

|







|











|







 







|







 







|










>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







|


<
<





<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

34
35
36
37
38
39
40

41
42
43
44
45
46
47
..
59
60
61
62
63
64
65

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

85
86
87
88

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
...
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
...
495
496
497
498
499
500
501
502
503
504


505
506
507
508
509























510
<li><a href="#extracting" style=text-decoration:none>Extracting Data From Database Cursors</a>
<li><a href="#change" style=text-decoration:none>Change these!!</a>

</ol>
<h1 style=clear:both>All LSM API Functions</h1>
<span style=display:block;float:left;width:35ex><a href=#lsm_begin>lsm_begin</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_checkpoint>lsm_checkpoint</a></span>

<span style=display:block;float:left;width:35ex><a href=#lsm_close>lsm_close</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_commit>lsm_commit</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_config>lsm_config</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_config_log>lsm_config_log</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_config_work_hook>lsm_config_work_hook</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_csr_close>lsm_csr_close</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_csr_cmp>lsm_csr_cmp</a></span>
................................................................................
<span style=display:block;float:left;width:35ex><a href=#lsm_flush>lsm_flush</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_free>lsm_free</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_info>lsm_info</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_insert>lsm_insert</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_new>lsm_new</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_open>lsm_open</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_rollback>lsm_rollback</a></span>

<span style=display:block;float:left;width:35ex><a href=#lsm_work>lsm_work</a></span>
<br style=clear:both>
<h1 style=clear:both>All LSM API Types</h1>
<span style=display:block;float:left;width:35ex><a href=#lsm_compress>lsm_compress</a></span>
<span style=display:block;float:left;width:35ex><a href=#lsm_env>lsm_env</a></span>
<br style=clear:both>
<h1>All LSM API Constants</h1>
<span style=display:block;float:left;width:35ex><a href=#LSM_BUSY>LSM_BUSY</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CANTOPEN>LSM_CANTOPEN</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_AUTOCHECKPOINT>LSM_CONFIG_AUTOCHECKPOINT</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_AUTOFLUSH>LSM_CONFIG_AUTOFLUSH</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_AUTOMERGE>LSM_CONFIG_AUTOMERGE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_AUTOWORK>LSM_CONFIG_AUTOWORK</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_BLOCK_SIZE>LSM_CONFIG_BLOCK_SIZE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_GET_COMPRESSION>LSM_CONFIG_GET_COMPRESSION</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_LOG_SIZE>LSM_CONFIG_LOG_SIZE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_MAX_FREELIST>LSM_CONFIG_MAX_FREELIST</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_MMAP>LSM_CONFIG_MMAP</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_MULTIPLE_PROCESSES>LSM_CONFIG_MULTIPLE_PROCESSES</a></span>

<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_PAGE_SIZE>LSM_CONFIG_PAGE_SIZE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_SAFETY>LSM_CONFIG_SAFETY</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_SET_COMPRESSION>LSM_CONFIG_SET_COMPRESSION</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_CONFIG_USE_LOG>LSM_CONFIG_USE_LOG</a></span>

<span style=display:block;float:left;width:35ex><a href=#LSM_CORRUPT>LSM_CORRUPT</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_ERROR>LSM_ERROR</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_FULL>LSM_FULL</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_ARRAY_PAGES>LSM_INFO_ARRAY_PAGES</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_ARRAY_STRUCTURE>LSM_INFO_ARRAY_STRUCTURE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_CHECKPOINT_SIZE>LSM_INFO_CHECKPOINT_SIZE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_DB_STRUCTURE>LSM_INFO_DB_STRUCTURE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_FREELIST>LSM_INFO_FREELIST</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_LOG_STRUCTURE>LSM_INFO_LOG_STRUCTURE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_NREAD>LSM_INFO_NREAD</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_NWRITE>LSM_INFO_NWRITE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_PAGE_ASCII_DUMP>LSM_INFO_PAGE_ASCII_DUMP</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_PAGE_HEX_DUMP>LSM_INFO_PAGE_HEX_DUMP</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_INFO_TREE_SIZE>LSM_INFO_TREE_SIZE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_IOERR>LSM_IOERR</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_MISUSE>LSM_MISUSE</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_MUTEX_GLOBAL>LSM_MUTEX_GLOBAL</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_MUTEX_HEAP>LSM_MUTEX_HEAP</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_NOMEM>LSM_NOMEM</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_OK>LSM_OK</a></span>
<span style=display:block;float:left;width:35ex><a href=#LSM_PROTOCOL>LSM_PROTOCOL</a></span>
................................................................................
lsm_env *lsm_default_env(void);
</verbatim>
<p>Return a pointer to the environment used by the database connection 
passed as the first argument. Assuming the argument is valid, this 
function always returns a valid environment pointer - it cannot fail.
The lsm_default_env() function returns a pointer to the default LSM
environment for the current platform.
<h2 id=configuring>Configuring a database connection.<a id=lsm_config></a><a id=LSM_CONFIG_AUTOFLUSH></a><a id=LSM_CONFIG_PAGE_SIZE></a><a id=LSM_CONFIG_SAFETY></a><a id=LSM_CONFIG_BLOCK_SIZE></a><a id=LSM_CONFIG_AUTOWORK></a><a id=LSM_CONFIG_LOG_SIZE></a><a id=LSM_CONFIG_MMAP></a><a id=LSM_CONFIG_USE_LOG></a><a id=LSM_CONFIG_AUTOMERGE></a><a id=LSM_CONFIG_MAX_FREELIST></a><a id=LSM_CONFIG_MULTIPLE_PROCESSES></a><a id=LSM_CONFIG_AUTOCHECKPOINT></a><a id=LSM_CONFIG_SET_COMPRESSION></a><a id=LSM_CONFIG_GET_COMPRESSION></a><a id=LSM_SAFETY_OFF></a><a id=LSM_SAFETY_NORMAL></a><a id=LSM_SAFETY_FULL></a></h2>
<verbatim>int lsm_config(lsm_db *, int, ...);
#define LSM_CONFIG_AUTOFLUSH           1
#define LSM_CONFIG_PAGE_SIZE           2
#define LSM_CONFIG_SAFETY              3
#define LSM_CONFIG_BLOCK_SIZE          4
#define LSM_CONFIG_AUTOWORK            5
#define LSM_CONFIG_LOG_SIZE            6
#define LSM_CONFIG_MMAP                7
#define LSM_CONFIG_USE_LOG             8
#define LSM_CONFIG_AUTOMERGE           9
#define LSM_CONFIG_MAX_FREELIST       10
#define LSM_CONFIG_MULTIPLE_PROCESSES 11
#define LSM_CONFIG_AUTOCHECKPOINT     12
#define LSM_CONFIG_SET_COMPRESSION    13
#define LSM_CONFIG_GET_COMPRESSION    14
#define LSM_SAFETY_OFF    0
#define LSM_SAFETY_NORMAL 1
#define LSM_SAFETY_FULL   2
</verbatim>
<p>The lsm_config() function is used to configure a database connection.
The following values may be passed as the second argument to lsm_config().
<p><dl><dt>LSM_CONFIG_AUTOFLUSH<dd>A read/write integer parameter. This value determines the maximum amount
of space (in bytes) used to accumulate writes in main-memory before 
they are flushed to a level 0 segment.
<p><dt>LSM_CONFIG_PAGE_SIZE<dd>A read/write integer parameter. This parameter may only be set before
lsm_open() has been called.
<p><dt>LSM_CONFIG_BLOCK_SIZE<dd>A read/write integer parameter. This parameter may only be set before
lsm_open() has been called.
<p><dt>LSM_CONFIG_LOG_SIZE<dd>A read/write integer parameter.
................................................................................
contains all successfully committed transactions.
<p><dt>LSM_CONFIG_AUTOWORK<dd>A read/write integer parameter.
<p><dt>LSM_CONFIG_AUTOCHECKPOINT<dd>A read/write integer parameter.
<p><dt>LSM_CONFIG_MMAP<dd>A read/write integer parameter. True to use mmap() to access the 
database file. False otherwise.
<p><dt>LSM_CONFIG_USE_LOG<dd>A read/write boolean parameter. True (the default) to use the log
file normally. False otherwise.
<p><dt>LSM_CONFIG_AUTOMERGE<dd>A read/write integer parameter. The minimum number of segments to
merge together at a time. Default value 4.
<p><dt>LSM_CONFIG_MAX_FREELIST<dd>A read/write integer parameter. The maximum number of free-list 
entries that are stored in a database checkpoint (the others are
stored elsewhere in the database).
<p>There is no reason for an application to configure or query this
parameter. It is only present because configuring a small value
makes certain parts of the lsm code easier to test.
................................................................................
<verbatim>void *lsm_malloc(lsm_env*, size_t);
void *lsm_realloc(lsm_env*, void *, size_t);
void lsm_free(lsm_env*, void *);
</verbatim>
<p>Invoke the memory allocation functions that belong to environment
pEnv. Or the system defaults if no memory allocation functions have 
been registered.
<h2 id=querying>Querying a Connection For Operational Data<a id=lsm_info></a><a id=LSM_INFO_NWRITE></a><a id=LSM_INFO_NREAD></a><a id=LSM_INFO_DB_STRUCTURE></a><a id=LSM_INFO_LOG_STRUCTURE></a><a id=LSM_INFO_ARRAY_STRUCTURE></a><a id=LSM_INFO_PAGE_ASCII_DUMP></a><a id=LSM_INFO_PAGE_HEX_DUMP></a><a id=LSM_INFO_FREELIST></a><a id=LSM_INFO_ARRAY_PAGES></a><a id=LSM_INFO_CHECKPOINT_SIZE></a><a id=LSM_INFO_TREE_SIZE></a></h2>
<verbatim>int lsm_info(lsm_db *, int, ...);
#define LSM_INFO_NWRITE           1
#define LSM_INFO_NREAD            2
#define LSM_INFO_DB_STRUCTURE     3
#define LSM_INFO_LOG_STRUCTURE    4
#define LSM_INFO_ARRAY_STRUCTURE  5
#define LSM_INFO_PAGE_ASCII_DUMP  6
#define LSM_INFO_PAGE_HEX_DUMP    7
#define LSM_INFO_FREELIST         8
#define LSM_INFO_ARRAY_PAGES      9
#define LSM_INFO_CHECKPOINT_SIZE 10
#define LSM_INFO_TREE_SIZE       11
</verbatim>
<p>Query a database connection for operational statistics or data.
The following values may be passed as the second argument to lsm_info().
<p><dl><dt>LSM_INFO_NWRITE<dd>The third parameter should be of type (int *). The location pointed
to by the third parameter is set to the number of 4KB pages written to
the database file during the lifetime of this connection. 
<p><dt>LSM_INFO_NREAD<dd>The third parameter should be of type (int *). The location pointed
................................................................................
<p><dt>LSM_INFO_FREELIST<dd>The third argument should be of type (char **). The location pointed
to is populated with a pointer to a nul-terminated string containing
the string representation of a Tcl data-structure. The returned 
string should be eventually freed by the caller using lsm_free().
<p>The Tcl structure returned is a list containing one element for each
free block in the database. The element itself consists of two 
integers - the block number and the id of the snapshot that freed it.
<p><dt>LSM_INFO_CHECKPOINT_SIZE<dd>The third argument should be of type (int *). The location pointed to
by this argument is populated with the number of bytes written to the
database file since the most recent checkpoint.
<p><dt>LSM_INFO_TREE_SIZE<dd>If this value is passed as the second argument to an lsm_info() call, it
should be followed by two arguments of type (int *) (for a total of four
arguments).
<p>At any time, there are either one or two tree structures held in shared
memory that new database clients will access (there may also be additional
tree structures being used by older clients - this API does not provide
information on them). One tree structure - the current tree - is used to
accumulate new data written to the database. The other tree structure -
the old tree - is a read-only tree holding older data and may be flushed 
to disk at any time.
<p>Assuming no error occurs, the location pointed to by the first of the two
(int *) arguments is set to the size of the old in-memory tree in bytes.
The second is set to the size of the current, or live in-memory tree.
</dl><h2 id=opening>Opening and Closing Write Transactions<a id=lsm_begin></a><a id=lsm_commit></a><a id=lsm_rollback></a></h2>
<verbatim>int lsm_begin(lsm_db *pDb, int iLevel);
int lsm_commit(lsm_db *pDb, int iLevel);
int lsm_rollback(lsm_db *pDb, int iLevel);
</verbatim>
<p>These functions are used to open and close transactions and nested 
sub-transactions.
................................................................................
Attempt to checkpoint the current database snapshot. Return an LSM
error code if an error occurs or LSM_OK otherwise.
<p>If the current snapshot has already been checkpointed, calling this 
function is a no-op. In this case if pnByte is not NULL, *pnByte is
set to 0. Or, if the current snapshot is successfully checkpointed
by this function and pbCkpt is not NULL, *pnByte is set to the number
of bytes written to the database file since the previous checkpoint
(the same measure as returned by the LSM_INFO_CHECKPOINT_SIZE query).
<h2 id=opening>Opening and Closing Database Cursors<a id=lsm_csr_open></a><a id=lsm_csr_close></a></h2>
<verbatim>int lsm_csr_open(lsm_db *pDb, lsm_cursor **ppCsr);
int lsm_csr_close(lsm_cursor *pCsr);
</verbatim>
<p>Open and close a database cursor.
<h2 id=positioning>Positioning Database Cursors<a id=lsm_csr_seek></a><a id=lsm_csr_first></a><a id=lsm_csr_last></a><a id=lsm_csr_next></a><a id=lsm_csr_prev></a><a id=LSM_SEEK_LEFAST></a><a id=LSM_SEEK_LE></a><a id=LSM_SEEK_EQ></a><a id=LSM_SEEK_GE></a></h2>
<verbatim>int lsm_csr_seek(lsm_cursor *pCsr, const void *pKey, int nKey, int eSeek);
................................................................................
the pKey/nKey arguments with the key that the cursor passed as the first
argument currently points to. If the cursors key is less than, equal to
or greater than pKey/nKey, *piRes is set to less than, equal to or greater
than zero before returning. LSM_OK is returned in this case.
<p>Or, if an error occurs, an LSM error code is returned and the final 
value of *piRes is undefined. If the cursor does not point to a valid
key when this function is called, LSM_MISUSE is returned.
<h2 id=change>Change these!!<a id=lsm_config_log></a><a id=lsm_config_work_hook></a></h2>
<verbatim>void lsm_config_log(lsm_db *, void (*)(void *, int, const char *), void *);
void lsm_config_work_hook(lsm_db *, void (*)(lsm_db *, void *), void *);


</verbatim>
<p>Configure a callback to which debugging and other messages should 
be directed. Only useful for debugging lsm.
Configure a callback that is invoked if the database connection ever
writes to the database file.
























Changes to www/lsmusr.wiki

47
48
49
50
51
52
53
54

55
56
57
58
59
60
61
...
807
808
809
810
811
812
813
814
815


816
817
818
819
820
821
822

823
824
825
826
827
828
829
830
831
832
833
create applications that use LSM. The remaining sections discuss more
specialized topics. <a href=#data_durability>Section 4</a> discusses the
configuration parameter that influences transaction durability (the guarantees
offered with respect to recently committed transactions if a power failure 
occurs). <a href=#compressed_and_encrypted_databases>Section 5</a> explains
the interface provided by LSM that allow external data compression and/or
encryption functions to be used to create compressed and/or encrypted
databases. <i>Todo: Clarify exactly what section 6 is and link it to here</i>.


<h1 id=introduction_to_lsm>1. Introduction to LSM</h1>

<p>LSM is an embedded database library for key-value data, roughly similar
in scope to
<a href="http://www.oracle.com/technetwork/products/berkeleydb/overview/index.html">Berkeley DB</a>, 
<a href="http://code.google.com/p/leveldb/">LevelDB</a> or
................................................................................
  int iVal = -1;
  rc = lsm_config(db, LSM_CONFIG_AUTOFLUSH, &iVal);
</verbatim>

<dl>
  <dt> <a href=lsmapi.wiki#LSM_CONFIG_MMAP>LSM_CONFIG_MMAP</a>
  <dd> <p style=margin-top:0>
    This option may be set to either 1 (true) or 0 (false). If it is set to
    true and LSM is running on a system with a 64-bit address space, the


    entire database file is memory mapped. Or, if it is false or LSM is 
    running in a 32-bit address space, data is accessed using ordinary
    OS file read and write primitives. Memory mapping the database file
    can significantly improve the performance of read operations, as database 
    pages do not have to be copied from operating system buffers into user 
    space buffers before they can be examined. 


    <p>This option can only be set before lsm_open() is called on the database
    connection.

    <p>The default value is 1 (true).

  <dt> <a href=lsmapi.wiki#LSM_CONFIG_MULTIPLE_PROCESSES>LSM_CONFIG_MULTIPLE_PROCESSES</a>
  <dd> <p style=margin-top:0>
    This option may also be set to either 1 (true) or 0 (false). If it is
    set to 0, then the library assumes that all database clients are located 
    within the same process (have access to the same memory space). Assuming
    this means the library can avoid using OS file locking primitives to lock







|
>







 







<
|
>
>
|
|
|
|
<
|
<
>


<
|







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
...
808
809
810
811
812
813
814

815
816
817
818
819
820
821

822

823
824
825

826
827
828
829
830
831
832
833
create applications that use LSM. The remaining sections discuss more
specialized topics. <a href=#data_durability>Section 4</a> discusses the
configuration parameter that influences transaction durability (the guarantees
offered with respect to recently committed transactions if a power failure 
occurs). <a href=#compressed_and_encrypted_databases>Section 5</a> explains
the interface provided by LSM that allow external data compression and/or
encryption functions to be used to create compressed and/or encrypted
databases. <a href=#performance_tuning>Section 6</a> deals with the topic
of performance tuning.

<h1 id=introduction_to_lsm>1. Introduction to LSM</h1>

<p>LSM is an embedded database library for key-value data, roughly similar
in scope to
<a href="http://www.oracle.com/technetwork/products/berkeleydb/overview/index.html">Berkeley DB</a>, 
<a href="http://code.google.com/p/leveldb/">LevelDB</a> or
................................................................................
  int iVal = -1;
  rc = lsm_config(db, LSM_CONFIG_AUTOFLUSH, &iVal);
</verbatim>

<dl>
  <dt> <a href=lsmapi.wiki#LSM_CONFIG_MMAP>LSM_CONFIG_MMAP</a>
  <dd> <p style=margin-top:0>

    If LSM is running on a system with a 64-bit address space, this option
    may be set to either 1 (true) or 0 (false). On a 32-bit platform, it is
    always set to 0.
    <p> If it is set to true, the entire database file is memory mapped. Or, if
    it is false, data is accessed using ordinary OS file read and write
    primitives. Memory mapping the database file can significantly improve the
    performance of read operations, as database pages do not have to be copied

    from operating system buffers into user space buffers before they can be

    examined. 
    <p>This option can only be set before lsm_open() is called on the database
    connection.

    <p>The default value is 1 (true) on a 64-bit platform, and 0 otherwise.

  <dt> <a href=lsmapi.wiki#LSM_CONFIG_MULTIPLE_PROCESSES>LSM_CONFIG_MULTIPLE_PROCESSES</a>
  <dd> <p style=margin-top:0>
    This option may also be set to either 1 (true) or 0 (false). If it is
    set to 0, then the library assumes that all database clients are located 
    within the same process (have access to the same memory space). Assuming
    this means the library can avoid using OS file locking primitives to lock