AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Helpers */7static PCache* helperCreateCache(int bPurgeable){8 int rc;9 PCache *p = (PCache*)sqlite3_malloc(sqlite3PcacheSize());10 TEST_ASSERT_NOT_NULL(p);11 rc = sqlite3PcacheOpen(1024, 8, bPurgeable, 0, 0, p);12 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);13 return p;14}15 16static void helperDestroyCache(PCache *p){17 if( p ){18 /* Discard any remaining contents to be safe */19 sqlite3PcacheClear(p);20 sqlite3PcacheClose(p);21 sqlite3_free(p);22 }23}24 25static PgHdr* helperFetchPage(PCache *pCache, Pgno pgno){26 sqlite3_pcache_page *pLower = sqlite3PcacheFetch(pCache, pgno, 3);27 TEST_ASSERT_NOT_NULL(pLower);28 PgHdr *pPg = sqlite3PcacheFetchFinish(pCache, pgno, pLower);29 TEST_ASSERT_NOT_NULL(pPg);30 TEST_ASSERT_EQUAL_INT(pgno, (int)pPg->pgno);31 return pPg;32}33 34static int helperCountDirty(PCache *pCache){35 int n = 0;36 PgHdr *p;37 p = sqlite3PcacheDirtyList(pCache);38 while( p ){39 n++;40 p = p->pDirty;41 }42 return n;43}44 45static int helperDirtyListContains(PCache *pCache, PgHdr *pWant){46 PgHdr *p = sqlite3PcacheDirtyList(pCache);47 while( p ){48 if( p==pWant ) return 1;49 p = p->pDirty;50 }51 return 0;52}53 54void setUp(void) {55 int rc;56 rc = sqlite3_initialize();57 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);58 rc = sqlite3PcacheInitialize();59 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);60}61 62void tearDown(void) {63 sqlite3PcacheShutdown();64 sqlite3_shutdown();65}66 67/* Test that MakeClean clears flags and removes page from dirty list (single dirty page) */68void test_sqlite3PcacheMakeClean_clears_flags_and_removes_single_dirty(void){69 PCache *pc = helperCreateCache(1);70 71 PgHdr *p1 = helperFetchPage(pc, 1);72 PgHdr *p2 = helperFetchPage(pc, 2);73 74 /* Make page 1 dirty and add extra flags */75 sqlite3PcacheMakeDirty(p1);76 p1->flags |= (PGHDR_NEED_SYNC | PGHDR_WRITEABLE);77 78 TEST_ASSERT_TRUE(helperDirtyListContains(pc, p1));79 TEST_ASSERT_FALSE(helperDirtyListContains(pc, p2));80 TEST_ASSERT_TRUE((p1->flags & PGHDR_DIRTY)!=0);81 82 /* Clean page 1 */83 sqlite3PcacheMakeClean(p1);84 85 /* Flags updated */86 TEST_ASSERT_TRUE((p1->flags & PGHDR_CLEAN)!=0);87 TEST_ASSERT_FALSE((p1->flags & PGHDR_DIRTY)!=0);88 TEST_ASSERT_FALSE((p1->flags & PGHDR_NEED_SYNC)!=0);89 TEST_ASSERT_FALSE((p1->flags & PGHDR_WRITEABLE)!=0);90 91 /* Removed from dirty list */92 TEST_ASSERT_FALSE(helperDirtyListContains(pc, p1));93 TEST_ASSERT_EQUAL_INT(0, helperCountDirty(pc));94 95 /* Release pages */96 sqlite3PcacheRelease(p1);97 sqlite3PcacheRelease(p2);98 99 helperDestroyCache(pc);100}101 102/* Test that MakeClean removes a page from the middle of the dirty list */103void test_sqlite3PcacheMakeClean_removes_middle_from_dirty_list(void){104 PCache *pc = helperCreateCache(1);105 106 PgHdr *p1 = helperFetchPage(pc, 1);107 PgHdr *p2 = helperFetchPage(pc, 2);108 PgHdr *p3 = helperFetchPage(pc, 3);109 110 sqlite3PcacheMakeDirty(p1);111 sqlite3PcacheMakeDirty(p2);112 sqlite3PcacheMakeDirty(p3);113 114 TEST_ASSERT_EQUAL_INT(3, helperCountDirty(pc));115 TEST_ASSERT_TRUE(helperDirtyListContains(pc, p1));116 TEST_ASSERT_TRUE(helperDirtyListContains(pc, p2));117 TEST_ASSERT_TRUE(helperDirtyListContains(pc, p3));118 119 /* Clean middle page (pgno 2) */120 sqlite3PcacheMakeClean(p2);121 122 TEST_ASSERT_TRUE((p2->flags & PGHDR_CLEAN)!=0);123 TEST_ASSERT_FALSE(helperDirtyListContains(pc, p2));124 TEST_ASSERT_EQUAL_INT(2, helperCountDirty(pc));125 TEST_ASSERT_TRUE(helperDirtyListContains(pc, p1));126 TEST_ASSERT_TRUE(helperDirtyListContains(pc, p3));127 128 /* Clean remaining dirty pages then release */129 sqlite3PcacheMakeClean(p1);130 sqlite3PcacheMakeClean(p3);131 132 sqlite3PcacheRelease(p1);133 sqlite3PcacheRelease(p2);134 sqlite3PcacheRelease(p3);135 136 helperDestroyCache(pc);137}138 139/* Test MakeClean when nRef==0 (page is dirty but unreferenced): should succeed and page remains fetchable */140void test_sqlite3PcacheMakeClean_unref_zero_path_fetchable_after_clean(void){141 PCache *pc = helperCreateCache(1);142 143 PgHdr *p = helperFetchPage(pc, 10);144 sqlite3PcacheMakeDirty(p);145 146 /* Drop our ref to make nRef==0 while still dirty */147 sqlite3PcacheRelease(p);148 TEST_ASSERT_EQUAL_INT64(0, sqlite3PcachePageRefcount(p));149 150 /* Now clean it; this exercises the path that unpins the lower-level page */151 sqlite3PcacheMakeClean(p);152 153 /* Flags updated and no longer dirty */154 TEST_ASSERT_TRUE((p->flags & PGHDR_CLEAN)!=0);155 TEST_ASSERT_FALSE(helperDirtyListContains(pc, p));156 TEST_ASSERT_EQUAL_INT(0, helperCountDirty(pc));157 158 /* Page remains fetchable and should be the same PgHdr */159 sqlite3_pcache_page *pLower = sqlite3PcacheFetch(pc, 10, 0);160 TEST_ASSERT_NOT_NULL(pLower);161 PgHdr *pAgain = sqlite3PcacheFetchFinish(pc, 10, pLower);162 TEST_ASSERT_NOT_NULL(pAgain);163 TEST_ASSERT_EQUAL_PTR(p, pAgain);164 165 /* Release */166 sqlite3PcacheRelease(pAgain);167 168 helperDestroyCache(pc);169}170 171int main(void){172 UNITY_BEGIN();173 RUN_TEST(test_sqlite3PcacheMakeClean_clears_flags_and_removes_single_dirty);174 RUN_TEST(test_sqlite3PcacheMakeClean_removes_middle_from_dirty_list);175 RUN_TEST(test_sqlite3PcacheMakeClean_unref_zero_path_fetchable_after_clean);176 return UNITY_END();177}