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

Overview
Comment:Defer opening a bt database until it is first read.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d9560b73de51f4f4c085659af2c0e18d012375df
User & Date: dan 2014-02-15 20:29:44.221
Context
2014-02-17
09:26
Have the bt backend support "PRAGMA page_size". check-in: 5aca057cad user: dan tags: trunk
2014-02-15
20:29
Defer opening a bt database until it is first read. check-in: d9560b73de user: dan tags: trunk
17:04
Add some human readable text to the bt file header. Refuse to open a database (SQLITE_NOTADB) if a valid header cannot be located in the database or wal files. check-in: b942b91a3d user: dan tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/kvbt.c.
22
23
24
25
26
27
28



29
30
31
32
33
34
35
36
37
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
63
64
65
66
67
68
69
70
71

72
73

74
75
76
77
78
79
80
typedef struct KVBtCsr KVBtCsr;

/*
** An instance of an open connection to a bt_db store.  A subclass of KVStore.
*/
struct KVBt {
  KVStore base;                   /* Base class, must be first */



  bt_db *pDb;                     /* Database handle */
};

/*
** An instance of an open cursor pointing into an LSM store.  A subclass
** of KVCursor.
*/
struct KVBtCsr {
  KVCursor base;                  /* Base class. Must be first */
  bt_cursor *pCsr;                /* LSM cursor handle */
};
  
/*
** Begin a transaction or subtransaction.
*/
static int btBegin(KVStore *pKVStore, int iLevel){
  KVBt *p = (KVBt *)pKVStore;
  int rc;








  rc = sqlite4BtBegin(p->pDb, iLevel);
  pKVStore->iTransLevel = sqlite4BtTransactionLevel(p->pDb);
  return rc;
}

/*
** Commit a transaction or subtransaction.
*/
static int btCommitPhaseOne(KVStore *pKVStore, int iLevel){
  return SQLITE4_OK;
}
static int btCommitPhaseTwo(KVStore *pKVStore, int iLevel){
  KVBt *p = (KVBt *)pKVStore;
  int rc;

  rc = sqlite4BtCommit(p->pDb, iLevel);
  pKVStore->iTransLevel = sqlite4BtTransactionLevel(p->pDb);
  return rc;
}

/*
** Rollback a transaction or subtransaction.
*/
static int btRollback(KVStore *pKVStore, int iLevel){
  KVBt *p = (KVBt *)pKVStore;
  int rc;

  rc = sqlite4BtRollback(p->pDb, iLevel);
  pKVStore->iTransLevel = sqlite4BtTransactionLevel(p->pDb);

  return rc;
}

/*
** Revert a transaction back to what it was when it started.
*/
#if 0







>
>
>


















>
>
>
>
>
>
>
>














>










|
>
|
|
>







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
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
typedef struct KVBtCsr KVBtCsr;

/*
** An instance of an open connection to a bt_db store.  A subclass of KVStore.
*/
struct KVBt {
  KVStore base;                   /* Base class, must be first */
  const char *zFilename;          /* File to open */
  int bOpen;                      /* See above */
  int openrc;                     /* See above */
  bt_db *pDb;                     /* Database handle */
};

/*
** An instance of an open cursor pointing into an LSM store.  A subclass
** of KVCursor.
*/
struct KVBtCsr {
  KVCursor base;                  /* Base class. Must be first */
  bt_cursor *pCsr;                /* LSM cursor handle */
};
  
/*
** Begin a transaction or subtransaction.
*/
static int btBegin(KVStore *pKVStore, int iLevel){
  KVBt *p = (KVBt *)pKVStore;
  int rc;
  if( p->openrc ) return p->openrc;
  if( p->bOpen==0 ){
    p->openrc = rc = sqlite4BtOpen(p->pDb, p->zFilename);
    if( rc!=SQLITE4_OK ){
      return rc;
    }
    p->bOpen = 1;
  }
  rc = sqlite4BtBegin(p->pDb, iLevel);
  pKVStore->iTransLevel = sqlite4BtTransactionLevel(p->pDb);
  return rc;
}

/*
** Commit a transaction or subtransaction.
*/
static int btCommitPhaseOne(KVStore *pKVStore, int iLevel){
  return SQLITE4_OK;
}
static int btCommitPhaseTwo(KVStore *pKVStore, int iLevel){
  KVBt *p = (KVBt *)pKVStore;
  int rc;
  assert( p->bOpen==1 );
  rc = sqlite4BtCommit(p->pDb, iLevel);
  pKVStore->iTransLevel = sqlite4BtTransactionLevel(p->pDb);
  return rc;
}

/*
** Rollback a transaction or subtransaction.
*/
static int btRollback(KVStore *pKVStore, int iLevel){
  KVBt *p = (KVBt *)pKVStore;
  int rc = SQLITE4_OK;
  if( p->bOpen==1 ){
    rc = sqlite4BtRollback(p->pDb, iLevel);
    pKVStore->iTransLevel = sqlite4BtTransactionLevel(p->pDb);
  }
  return rc;
}

/*
** Revert a transaction back to what it was when it started.
*/
#if 0
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
*/
static int btReplace(
  KVStore *pKVStore,
  const KVByteArray *aKey, KVSize nKey,
  const KVByteArray *aData, KVSize nData
){
  KVBt *p = (KVBt *)pKVStore;

  return sqlite4BtReplace(p->pDb, aKey, nKey, aData, nData);
}

/*
** Create a new cursor object.
*/
static int btOpenCursor(KVStore *pKVStore, KVCursor **ppKVCursor){
  KVBt *p = (KVBt *)pKVStore;
  int rc = SQLITE4_OK;
  bt_cursor *pCsr;
  KVBtCsr *pBtcsr;


  rc = sqlite4BtCsrOpen(p->pDb, sizeof(KVBtCsr), &pCsr);
  if( rc!=SQLITE4_OK ){
    pBtcsr = 0;
  }else{
    pBtcsr = (KVBtCsr*)sqlite4BtCsrExtra(pCsr);
    memset(pBtcsr, 0, sizeof(KVBtCsr));
    pBtcsr->base.pStore = pKVStore;







>












>







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
*/
static int btReplace(
  KVStore *pKVStore,
  const KVByteArray *aKey, KVSize nKey,
  const KVByteArray *aData, KVSize nData
){
  KVBt *p = (KVBt *)pKVStore;
  assert( p->bOpen==1 );
  return sqlite4BtReplace(p->pDb, aKey, nKey, aData, nData);
}

/*
** Create a new cursor object.
*/
static int btOpenCursor(KVStore *pKVStore, KVCursor **ppKVCursor){
  KVBt *p = (KVBt *)pKVStore;
  int rc = SQLITE4_OK;
  bt_cursor *pCsr;
  KVBtCsr *pBtcsr;

  assert( p->bOpen==1 );
  rc = sqlite4BtCsrOpen(p->pDb, sizeof(KVBtCsr), &pCsr);
  if( rc!=SQLITE4_OK ){
    pBtcsr = 0;
  }else{
    pBtcsr = (KVBtCsr*)sqlite4BtCsrExtra(pCsr);
    memset(pBtcsr, 0, sizeof(KVBtCsr));
    pBtcsr->base.pStore = pKVStore;
213
214
215
216
217
218
219

220
221
222
223
224
225
226
227
228
229

230
231
232
233
234

235
236
237
238
239
240
241
}

/*
** Destructor for the entire in-memory storage tree.
*/
static int btClose(KVStore *pKVStore){
  KVBt *p = (KVBt *)pKVStore;

  return sqlite4BtClose(p->pDb);
}

static int btControl(KVStore *pKVStore, int op, void *pArg){
  KVBt *p = (KVBt *)pKVStore;
  return sqlite4BtControl(p->pDb, op, pArg);
}

static int btGetMeta(KVStore *pKVStore, unsigned int *piVal){
  KVBt *p = (KVBt *)pKVStore;

  return sqlite4BtGetCookie(p->pDb, piVal);
}

static int btPutMeta(KVStore *pKVStore, unsigned int iVal){
  KVBt *p = (KVBt *)pKVStore;

  return sqlite4BtSetCookie(p->pDb, iVal);
}

static int btGetMethod(
  sqlite4_kvstore *pKVStore, 
  const char *zMethod, 
  void **ppArg,







>










>





>







229
230
231
232
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
}

/*
** Destructor for the entire in-memory storage tree.
*/
static int btClose(KVStore *pKVStore){
  KVBt *p = (KVBt *)pKVStore;
  sqlite4_free(pKVStore->pEnv, p->zFilename);
  return sqlite4BtClose(p->pDb);
}

static int btControl(KVStore *pKVStore, int op, void *pArg){
  KVBt *p = (KVBt *)pKVStore;
  return sqlite4BtControl(p->pDb, op, pArg);
}

static int btGetMeta(KVStore *pKVStore, unsigned int *piVal){
  KVBt *p = (KVBt *)pKVStore;
  assert( p->bOpen==1 );
  return sqlite4BtGetCookie(p->pDb, piVal);
}

static int btPutMeta(KVStore *pKVStore, unsigned int iVal){
  KVBt *p = (KVBt *)pKVStore;
  assert( p->bOpen==1 );
  return sqlite4BtSetCookie(p->pDb, iVal);
}

static int btGetMethod(
  sqlite4_kvstore *pKVStore, 
  const char *zMethod, 
  void **ppArg,
278
279
280
281
282
283
284

285
286
287
288

289
290
291
292
293
294
295
296
297
298
299

  KVBt *pNew = 0;
  bt_db *pDb = 0;
  int rc;

  rc = sqlite4BtNew(pEnv, sizeof(KVBt), &pDb);
  if( rc==SQLITE4_OK ){

    pNew = (KVBt*)sqlite4BtExtra(pDb);
    pNew->base.pStoreVfunc = &bt_methods;
    pNew->base.pEnv = pEnv;
    pNew->pDb = pDb;

    rc = sqlite4BtOpen(pDb, zFilename);
  }

  if( rc!=SQLITE4_OK && pDb ){
    sqlite4BtClose(pDb);
    pNew = 0;
  }
  *ppKVStore = pNew;
  return rc;
}








>




>
|










297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

  KVBt *pNew = 0;
  bt_db *pDb = 0;
  int rc;

  rc = sqlite4BtNew(pEnv, sizeof(KVBt), &pDb);
  if( rc==SQLITE4_OK ){
    bt_env *pBtenv = 0;
    pNew = (KVBt*)sqlite4BtExtra(pDb);
    pNew->base.pStoreVfunc = &bt_methods;
    pNew->base.pEnv = pEnv;
    pNew->pDb = pDb;
    sqlite4BtControl(pDb, BT_CONTROL_GETVFS, (void*)&pBtenv);
    rc = pBtenv->xFullpath(pEnv, pBtenv, zFilename, &pNew->zFilename);
  }

  if( rc!=SQLITE4_OK && pDb ){
    sqlite4BtClose(pDb);
    pNew = 0;
  }
  *ppKVStore = pNew;
  return rc;
}

Changes to test/attach.test.
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
      puts "\n**** Tests do not work when run as root ****"
      forcedelete cannot-read
      exit 1
    }
    catchsql {
      ATTACH DATABASE 'cannot-read' AS noread;
    }
  } {1 {unable to open database: cannot-read}}
  do_test attach-6.2.2 {
    db errorcode
  } {10}
  forcedelete cannot-read
}

# Check the error message if we try to access a database that has







|







745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
      puts "\n**** Tests do not work when run as root ****"
      forcedelete cannot-read
      exit 1
    }
    catchsql {
      ATTACH DATABASE 'cannot-read' AS noread;
    }
  } {1 {disk I/O error}}
  do_test attach-6.2.2 {
    db errorcode
  } {10}
  forcedelete cannot-read
}

# Check the error message if we try to access a database that has
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
do_test attach-8.1 {
  set fd [open test2.db w]
  puts $fd "This file is not a valid SQLite database"
  close $fd
  catchsql {
    ATTACH 'test2.db' AS t2;
  }
} {1 {unable to open database: test2.db}}
do_test attach-8.2 {
  db errorcode
} {26}
forcedelete test2.db
do_test attach-8.3 {
  sqlite4 db2 test2.db
  db2 eval {CREATE TABLE t1(x); BEGIN EXCLUSIVE}







|







787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
do_test attach-8.1 {
  set fd [open test2.db w]
  puts $fd "This file is not a valid SQLite database"
  close $fd
  catchsql {
    ATTACH 'test2.db' AS t2;
  }
} {1 {file is encrypted or is not a database}}
do_test attach-8.2 {
  db errorcode
} {26}
forcedelete test2.db
do_test attach-8.3 {
  sqlite4 db2 test2.db
  db2 eval {CREATE TABLE t1(x); BEGIN EXCLUSIVE}
Changes to test/attach3.test.
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# Failure to attach leaves us in a workable state.
# Ticket #811
#
do_test attach3-11.0 {
  catchsql {
    ATTACH DATABASE '/nodir/nofile.x' AS notadb;
  }
} {1 {unable to open database: /nodir/nofile.x}}
do_test attach3-11.1 {
  catchsql {
    ATTACH DATABASE ':memory:' AS notadb;
  }
} {0 {}}
do_test attach3-11.2 {
  catchsql {







|







235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# Failure to attach leaves us in a workable state.
# Ticket #811
#
do_test attach3-11.0 {
  catchsql {
    ATTACH DATABASE '/nodir/nofile.x' AS notadb;
  }
} {1 {disk I/O error}}
do_test attach3-11.1 {
  catchsql {
    ATTACH DATABASE ':memory:' AS notadb;
  }
} {0 {}}
do_test attach3-11.2 {
  catchsql {
Changes to test/bt1.test.
44
45
46
47
48
49
50
51

52
53
54
55
56
57
58
  execsql { SELECT * FROM t1 }
} {abcd}

do_test 1.3 { 
  db close
  hexio_write test.db  8 55555555

  list [catch {sqlite4 db test.db} msg] $msg

} {1 {file is encrypted or is not a database}}

#-------------------------------------------------------------------------
# Test that, if there is a *-wal file that contains a valid copy of page
# 1 (with the db header), it is possible to open the database even if
# the header at byte offset 0 is damaged.
#







|
>







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  execsql { SELECT * FROM t1 }
} {abcd}

do_test 1.3 { 
  db close
  hexio_write test.db  8 55555555

  sqlite4 db test.db
  catchsql { SELECT * FROM t1 }
} {1 {file is encrypted or is not a database}}

#-------------------------------------------------------------------------
# Test that, if there is a *-wal file that contains a valid copy of page
# 1 (with the db header), it is possible to open the database even if
# the header at byte offset 0 is damaged.
#
Changes to test/fault1.test.
11
12
13
14
15
16
17


18
19
20
21
22
23
24
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix fault1




do_faultsim_test 1.0 -faults oom* -body {
  execsql { SELECT * FROM sqlite_master }
} -test {
  faultsim_test_result {0 {}} 
}








>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix fault1


execsql { SELECT *  FROM  sqlite_master }

do_faultsim_test 1.0 -faults oom* -body {
  execsql { SELECT * FROM sqlite_master }
} -test {
  faultsim_test_result {0 {}} 
}

Changes to test/permutations.test.
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#   full
#
lappend ::testsuitelist xxx

test_suite "bt" -prefix "bt-" -description {
} -files {
bt1.test

aggerror.test
alter.test
alter3.test
alter4.test
analyze.test
analyze3.test
analyze4.test







<







131
132
133
134
135
136
137

138
139
140
141
142
143
144
#   full
#
lappend ::testsuitelist xxx

test_suite "bt" -prefix "bt-" -description {
} -files {
bt1.test

aggerror.test
alter.test
alter3.test
alter4.test
analyze.test
analyze3.test
analyze4.test