AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5/* Wrapper for the static function under test (provided by build harness) */6#ifndef SQLITE_OMIT_SHARED_CACHE7extern int test_setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock);8#endif9 10/* Helpers to find and count locks for a given (Btree*, iTable) */11#ifndef SQLITE_OMIT_SHARED_CACHE12static BtLock* findLock(Btree *p, Pgno iTable){13 BtLock *pIter = p->pBt->pLock;14 while( pIter ){15 if( pIter->pBtree==p && pIter->iTable==(u32)iTable ){16 return pIter;17 }18 pIter = pIter->pNext;19 }20 return NULL;21}22static int countLocks(Btree *p, Pgno iTable){23 int c = 0;24 BtLock *pIter = p->pBt->pLock;25 while( pIter ){26 if( pIter->pBtree==p && pIter->iTable==(u32)iTable ) c++;27 pIter = pIter->pNext;28 }29 return c;30}31#endif32 33/* Utility to open a sharable Btree on a file */34#ifndef SQLITE_OMIT_SHARED_CACHE35static void openSharableBtree(const char *zFile, sqlite3 **ppDb, Btree **ppBt){36 int rc;37 sqlite3 *db = 0;38 sqlite3_vfs *pVfs = sqlite3_vfs_find(0);39 Btree *pBt = 0;40 41 rc = sqlite3_open_v2(":memory:", &db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, 0);42 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);43 TEST_ASSERT_NOT_NULL(db);44 45 /* Open the Btree directly with SHAREDCACHE flag to ensure p->sharable==1 */46 sqlite3_mutex_enter(db->mutex);47 rc = sqlite3BtreeOpen(pVfs, zFile, db, &pBt, 0,48 SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_SHAREDCACHE);49 sqlite3_mutex_leave(db->mutex);50 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);51 TEST_ASSERT_NOT_NULL(pBt);52 TEST_ASSERT_TRUE_MESSAGE(pBt->sharable!=0, "Btree is not sharable; shared-cache likely disabled");53 54 *ppDb = db;55 *ppBt = pBt;56}57#endif58 59/* Utility to close a Btree and its owning db */60#ifndef SQLITE_OMIT_SHARED_CACHE61static void closeBtreeAndDb(sqlite3 *db, Btree *pBt){62 if( db && pBt ){63 sqlite3_mutex_enter(db->mutex);64 /* Ensure any open transaction is committed/ended before closing */65 (void)sqlite3BtreeCommit(pBt);66 (void)sqlite3BtreeClose(pBt);67 sqlite3_mutex_leave(db->mutex);68 }69 if( db ){70 sqlite3_close(db);71 }72}73#endif74 75void setUp(void) {76 /* nothing */77}78 79void tearDown(void) {80 /* nothing */81}82 83#ifndef SQLITE_OMIT_SHARED_CACHE84/* Basic READ lock creation */85void test_setSharedCacheTableLock_add_read_lock(void){86 sqlite3 *db = 0;87 Btree *pBt = 0;88 const Pgno iTable = 2; /* avoid schema table 1 */89 90 openSharableBtree("test_sc_readlock.db", &db, &pBt);91 92 /* Call the function under test while holding required mutex/enter */93 sqlite3_mutex_enter(db->mutex);94 sqlite3BtreeEnter(pBt);95 /* Precondition: querySharedCacheTableLock() should be OK for READ_LOCK.96 The assert inside the target function requires this. */97 {98 int rcQ = SQLITE_OK; /* no-op in non-debug or ensures correctness */99 (void)rcQ;100 }101 int rc = test_setSharedCacheTableLock(pBt, iTable, READ_LOCK);102 sqlite3BtreeLeave(pBt);103 sqlite3_mutex_leave(db->mutex);104 105 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);106 107 /* Verify a BtLock exists for this (Btree,iTable) with READ_LOCK */108 BtLock *pLk = findLock(pBt, iTable);109 TEST_ASSERT_NOT_NULL(pLk);110 TEST_ASSERT_EQUAL_PTR(pBt, pLk->pBtree);111 TEST_ASSERT_EQUAL_UINT32(iTable, pLk->iTable);112 TEST_ASSERT_EQUAL_INT(READ_LOCK, pLk->eLock);113 114 closeBtreeAndDb(db, pBt);115}116 117/* Upgrade from READ to WRITE lock */118void test_setSharedCacheTableLock_upgrade_to_write(void){119 sqlite3 *db = 0;120 Btree *pBt = 0;121 const Pgno iTable = 2;122 123 openSharableBtree("test_sc_upgrade.db", &db, &pBt);124 125 /* First, add a READ lock */126 sqlite3_mutex_enter(db->mutex);127 sqlite3BtreeEnter(pBt);128 TEST_ASSERT_EQUAL_INT(SQLITE_OK, test_setSharedCacheTableLock(pBt, iTable, READ_LOCK));129 sqlite3BtreeLeave(pBt);130 sqlite3_mutex_leave(db->mutex);131 132 /* Begin a write transaction to satisfy WRITE_LOCK asserts */133 sqlite3_mutex_enter(db->mutex);134 int rc = sqlite3BtreeBeginTrans(pBt, 1, 0);135 sqlite3_mutex_leave(db->mutex);136 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);137 138 /* Now upgrade to WRITE lock */139 sqlite3_mutex_enter(db->mutex);140 sqlite3BtreeEnter(pBt);141 rc = test_setSharedCacheTableLock(pBt, iTable, WRITE_LOCK);142 sqlite3BtreeLeave(pBt);143 sqlite3_mutex_leave(db->mutex);144 145 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);146 147 /* Verify lock exists and is WRITE */148 BtLock *pLk = findLock(pBt, iTable);149 TEST_ASSERT_NOT_NULL(pLk);150 TEST_ASSERT_EQUAL_INT(WRITE_LOCK, pLk->eLock);151 152 /* Clean up transaction */153 sqlite3_mutex_enter(db->mutex);154 (void)sqlite3BtreeCommit(pBt);155 sqlite3_mutex_leave(db->mutex);156 157 closeBtreeAndDb(db, pBt);158}159 160/* Ensure READ after WRITE does not downgrade the lock */161void test_setSharedCacheTableLock_no_downgrade_on_read_after_write(void){162 sqlite3 *db = 0;163 Btree *pBt = 0;164 const Pgno iTable = 2;165 166 openSharableBtree("test_sc_nodowngrade.db", &db, &pBt);167 168 /* Begin write transaction and set WRITE lock */169 sqlite3_mutex_enter(db->mutex);170 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3BtreeBeginTrans(pBt, 1, 0));171 sqlite3_mutex_leave(db->mutex);172 173 sqlite3_mutex_enter(db->mutex);174 sqlite3BtreeEnter(pBt);175 TEST_ASSERT_EQUAL_INT(SQLITE_OK, test_setSharedCacheTableLock(pBt, iTable, WRITE_LOCK));176 sqlite3BtreeLeave(pBt);177 sqlite3_mutex_leave(db->mutex);178 179 /* Now call with READ_LOCK — should remain WRITE_LOCK */180 sqlite3_mutex_enter(db->mutex);181 sqlite3BtreeEnter(pBt);182 TEST_ASSERT_EQUAL_INT(SQLITE_OK, test_setSharedCacheTableLock(pBt, iTable, READ_LOCK));183 sqlite3BtreeLeave(pBt);184 sqlite3_mutex_leave(db->mutex);185 186 BtLock *pLk = findLock(pBt, iTable);187 TEST_ASSERT_NOT_NULL(pLk);188 TEST_ASSERT_EQUAL_INT(WRITE_LOCK, pLk->eLock);189 190 /* Ensure only one lock entry exists for this (pBt,iTable) */191 TEST_ASSERT_EQUAL_INT(1, countLocks(pBt, iTable));192 193 /* Clean up */194 sqlite3_mutex_enter(db->mutex);195 (void)sqlite3BtreeCommit(pBt);196 sqlite3_mutex_leave(db->mutex);197 closeBtreeAndDb(db, pBt);198}199 200/* Multiple calls should not create duplicate BtLock entries */201void test_setSharedCacheTableLock_no_duplicate_entries(void){202 sqlite3 *db = 0;203 Btree *pBt = 0;204 const Pgno iTable = 2;205 206 openSharableBtree("test_sc_nodup.db", &db, &pBt);207 208 sqlite3_mutex_enter(db->mutex);209 sqlite3BtreeEnter(pBt);210 TEST_ASSERT_EQUAL_INT(SQLITE_OK, test_setSharedCacheTableLock(pBt, iTable, READ_LOCK));211 TEST_ASSERT_EQUAL_INT(SQLITE_OK, test_setSharedCacheTableLock(pBt, iTable, READ_LOCK));212 TEST_ASSERT_EQUAL_INT(SQLITE_OK, test_setSharedCacheTableLock(pBt, iTable, READ_LOCK));213 sqlite3BtreeLeave(pBt);214 sqlite3_mutex_leave(db->mutex);215 216 TEST_ASSERT_EQUAL_INT(1, countLocks(pBt, iTable));217 BtLock *pLk = findLock(pBt, iTable);218 TEST_ASSERT_NOT_NULL(pLk);219 TEST_ASSERT_EQUAL_INT(READ_LOCK, pLk->eLock);220 221 closeBtreeAndDb(db, pBt);222}223#else /* SQLITE_OMIT_SHARED_CACHE */224void test_setSharedCacheTableLock_add_read_lock(void){ TEST_IGNORE_MESSAGE("Shared cache omitted at build time"); }225void test_setSharedCacheTableLock_upgrade_to_write(void){ TEST_IGNORE_MESSAGE("Shared cache omitted at build time"); }226void test_setSharedCacheTableLock_no_downgrade_on_read_after_write(void){ TEST_IGNORE_MESSAGE("Shared cache omitted at build time"); }227void test_setSharedCacheTableLock_no_duplicate_entries(void){ TEST_IGNORE_MESSAGE("Shared cache omitted at build time"); }228#endif /* SQLITE_OMIT_SHARED_CACHE */229 230int main(void){231 UNITY_BEGIN();232 RUN_TEST(test_setSharedCacheTableLock_add_read_lock);233 RUN_TEST(test_setSharedCacheTableLock_upgrade_to_write);234 RUN_TEST(test_setSharedCacheTableLock_no_downgrade_on_read_after_write);235 RUN_TEST(test_setSharedCacheTableLock_no_duplicate_entries);236 return UNITY_END();237}