Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add an LRU cache of uncompressed frame content to the zonefile virtual table implementation. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | zonefile |
Files: | files | file ages | folders |
SHA3-256: |
883e7e75d65622e8d06c46e48b7cc756 |
User & Date: | dan 2018-02-22 16:46:42.652 |
Context
2018-02-22
| ||
21:06 | Add tests cases and fix some minor zonefile problems. (check-in: f4d42162fa user: dan tags: zonefile) | |
16:46 | Add an LRU cache of uncompressed frame content to the zonefile virtual table implementation. (check-in: 883e7e75d6 user: dan tags: zonefile) | |
2018-02-21
| ||
21:15 | Modifications to the zonefile module to make it easier to add a cache of uncompressed frame content. (check-in: d9d5cc62f1 user: dan tags: zonefile) | |
Changes
Changes to ext/zonefile/zonefile.c.
︙ | ︙ | |||
1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 | const char *zKey = (const char*)sqlite3_value_text(apVal[3]); rc = zonefileKeyStore(pTab->pGlobal, pTab->zDb, pTab->zBase,iFileid,zKey); } } return rc; } typedef struct ZonefileTab ZonefileTab; struct ZonefileTab { sqlite3_vtab base; /* Base class - must be first */ sqlite3 *db; sqlite3_stmt *pIdToName; /* Translate fileid to filename */ ZonefileGlobal *pGlobal; char *zName; /* Name of this table */ char *zDb; /* Name of db containing this table */ | > > > > > > > > > > > > > > > | > > > > > < < < < < < < < | 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 | const char *zKey = (const char*)sqlite3_value_text(apVal[3]); rc = zonefileKeyStore(pTab->pGlobal, pTab->zDb, pTab->zBase,iFileid,zKey); } } return rc; } /* Each entry in the frame-cache is represented by an instance of the ** following structure. */ typedef struct ZonefileFrame ZonefileFrame; struct ZonefileFrame { i64 iFileid; /* Fileid for this frame */ i64 iFrameOff; /* Offset of frame in file */ int nBuf; /* Size of aBuf[] in bytes */ u8 *aBuf; /* Buffer containing uncompressed frame data */ ZonefileFrame *pLruNext; /* Next element in LRU list */ ZonefileFrame *pLruPrev; /* Previous element in LRU list */ ZonefileFrame *pHashNext; /* Next element in same hash bucket */ }; typedef struct ZonefileTab ZonefileTab; struct ZonefileTab { sqlite3_vtab base; /* Base class - must be first */ sqlite3 *db; sqlite3_stmt *pIdToName; /* Translate fileid to filename */ ZonefileGlobal *pGlobal; char *zName; /* Name of this table */ char *zDb; /* Name of db containing this table */ /* The following variables are used to implement the frame-cache */ int nCacheSize; /* Configured cache size */ int nCacheEntry; /* Current number of entries in cache */ int nCacheBucket; /* Number of buckets in frame cache hash table */ ZonefileFrame **aCache; /* Array of hash buckets */ ZonefileFrame *pCacheFirst;/* Most recently used frame */ ZonefileFrame *pCacheLast; /* Least recently used frame (first to discard) */ }; typedef struct ZonefileCsr ZonefileCsr; struct ZonefileCsr { sqlite3_vtab_cursor base; /* Base class - must be first */ sqlite3_stmt *pSelect; /* SELECT on %_shadow_idx table */ }; /* ** Attempt to interpret the contents of string z as an integer. If ** successful, set (*piVal) to the integer value and return SQLITE_OK. ** Otherwise, return SQLITE_ERROR. */ static int zonefileParseInteger(const char *z, int *piVal){ *piVal = atoi(z); |
︙ | ︙ | |||
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 | if( rc==SQLITE_OK ){ rc = sqlite3_declare_vtab(db, ZONEFILE_SCHEMA); } for(i=3; i<argc && rc==SQLITE_OK; i++){ zonefileParseOption(p, argv[i], pzErr); } } if( rc!=SQLITE_OK ){ sqlite3_free(p); p = 0; } *ppVtab = (sqlite3_vtab*)p; | > | 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 | if( rc==SQLITE_OK ){ rc = sqlite3_declare_vtab(db, ZONEFILE_SCHEMA); } for(i=3; i<argc && rc==SQLITE_OK; i++){ zonefileParseOption(p, argv[i], pzErr); } if( rc==SQLITE_OK && p->nCacheSize<1 ) p->nCacheSize = 1; } if( rc!=SQLITE_OK ){ sqlite3_free(p); p = 0; } *ppVtab = (sqlite3_vtab*)p; |
︙ | ︙ | |||
2104 2105 2106 2107 2108 2109 2110 | int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ return zonefileCreateConnect(0, pAux, db, argc, argv, ppVtab, pzErr); } | < < < < < < < < < < | 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 | int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ return zonefileCreateConnect(0, pAux, db, argc, argv, ppVtab, pzErr); } /* ** Zonefile virtual table module xBestIndex method. ** ** Equality and range constraints on either the rowid or column "k" (which ** are the same thing) are processed. Bits in the idxNum parameter are ** set to indicate the constraints present: ** |
︙ | ︙ | |||
2187 2188 2189 2190 2191 2192 2193 | pInfo->idxNum = idxNum; pInfo->estimatedCost = cost; return SQLITE_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < | 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 | pInfo->idxNum = idxNum; pInfo->estimatedCost = cost; return SQLITE_OK; } /* ** zonefile virtual table module xOpen method. */ static int zonefileOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ ZonefileCsr *pCsr; pCsr = (ZonefileCsr*)sqlite3_malloc(sizeof(ZonefileCsr)); if( pCsr==0 ){ |
︙ | ︙ | |||
2316 2317 2318 2319 2320 2321 2322 | return (pCsr->pSelect==0); } static void zonefileFree(void *p){ sqlite3_free(p); } | < < < < < < < < < < < < < < < < < < < < < < | 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 | return (pCsr->pSelect==0); } static void zonefileFree(void *p){ sqlite3_free(p); } static int zonefileGetFile( sqlite3_context *pCtx, /* Leave error message here */ ZonefileCsr *pCsr, /* Cursor object */ const char **pzFile /* OUT: Pointer to current file */ ){ ZonefileTab *pTab = (ZonefileTab*)pCsr->base.pVtab; int rc = SQLITE_OK; |
︙ | ︙ | |||
2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 | } zonefileFileClose(pFd); sqlite3_free(aBuf); return rc; } static ZonefileFrame *zonefileCacheFind( ZonefileTab *pTab, i64 iFile, i64 iFrameOff ){ return 0; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > | > > | 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 | } zonefileFileClose(pFd); sqlite3_free(aBuf); return rc; } #ifndef NDEBUG static void zonefileCacheCheck(ZonefileTab *pTab){ ZonefileFrame *p; int n = 0; for(p=pTab->pCacheFirst; p; p=p->pLruNext){ assert( p!=pTab->pCacheFirst || p->pLruPrev==0 ); assert( p!=pTab->pCacheLast || p->pLruNext==0 ); assert( p==pTab->pCacheFirst || p->pLruPrev->pLruNext==p ); assert( p==pTab->pCacheLast || p->pLruNext->pLruPrev==p ); n++; } assert( n==pTab->nCacheEntry ); } #else # define zonefileCacheCheck(x) #endif /* ** Search the frame-cache belonging to virtual table pTab for an entry ** corresponding to the frame at byte offset iFrameOff of the file with ** file id iFile. If such an entry is found, return a pointer to it. ** Otherwise, if no such entry exists, return NULL. */ static ZonefileFrame *zonefileCacheFind( ZonefileTab *pTab, i64 iFile, i64 iFrameOff ){ ZonefileFrame *pFrame; for(pFrame=pTab->pCacheFirst; pFrame; pFrame=pFrame->pLruNext){ if( pFrame->iFileid==iFile && pFrame->iFrameOff==iFrameOff ){ /* Found a match. Move it to the front of the LRU list and return ** a pointer to it. */ assert( (pFrame->pLruPrev==0)==(pFrame==pTab->pCacheFirst) ); assert( (pFrame->pLruNext==0)==(pFrame==pTab->pCacheLast) ); if( pFrame->pLruPrev ){ assert( pFrame==pFrame->pLruPrev->pLruNext ); pFrame->pLruPrev->pLruNext = pFrame->pLruNext; if( pFrame->pLruNext ){ assert( pFrame==pFrame->pLruNext->pLruPrev ); pFrame->pLruNext->pLruPrev = pFrame->pLruPrev; }else{ assert( pFrame==pTab->pCacheLast ); pTab->pCacheLast = pFrame->pLruPrev; pTab->pCacheLast->pLruNext = 0; } pFrame->pLruPrev = 0; pFrame->pLruNext = pTab->pCacheFirst; pTab->pCacheFirst->pLruPrev = pFrame; pTab->pCacheFirst = pFrame; } zonefileCacheCheck(pTab); return pFrame; } } return 0; } /* ** Return the index of the hash bucket that iFileid/iFrameOff belongs to. */ int zonefileCacheHash(ZonefileTab *pTab, i64 iFileid, i64 iFrameOff){ u32 h; h = (iFileid & 0xFFFFFFFF) ^ (iFrameOff & 0xFFFFFFFF); return (h % pTab->nCacheBucket); } /* ** Store the frame object passed as the second argument in the frame ** cache belonging to table pTab. */ static int zonefileCacheStore(ZonefileTab *pTab, ZonefileFrame *pFrame){ int h; /* Allocate the hash table if it has not already been allocated. */ if( pTab->aCache==0 ){ int nByte = pTab->nCacheSize * 2 * sizeof(ZonefileFrame*); pTab->aCache = (ZonefileFrame**)sqlite3_malloc(nByte); if( pTab->aCache==0 ){ sqlite3_free(pFrame); return SQLITE_NOMEM; } memset(pTab->aCache, 0, nByte); pTab->nCacheBucket = pTab->nCacheSize * 2; } /* Add the new entry to the hash table */ h = zonefileCacheHash(pTab, pFrame->iFileid, pFrame->iFrameOff); assert( h>=0 && h<pTab->nCacheBucket ); pFrame->pHashNext = pTab->aCache[h]; pTab->aCache[h] = pFrame; /* Add the new entry to the LRU list */ pFrame->pLruPrev = 0; pFrame->pLruNext = pTab->pCacheFirst; pTab->pCacheFirst = pFrame; if( pFrame->pLruNext==0 ){ pTab->pCacheLast = pFrame; }else{ pFrame->pLruNext->pLruPrev = pFrame; } pTab->nCacheEntry++; if( pTab->nCacheEntry>pTab->nCacheSize ){ ZonefileFrame **pp; /* Remove the oldest entry from the LRU list. */ ZonefileFrame *pLast = pTab->pCacheLast; assert( pTab->pCacheLast ); assert( pTab->nCacheEntry>1 ); pTab->pCacheLast = pLast->pLruPrev; pTab->pCacheLast->pLruNext = 0; pTab->nCacheEntry--; /* Remove the same entry from the hash table. */ h = zonefileCacheHash(pTab, pLast->iFileid, pLast->iFrameOff); assert( h>=0 && h<pTab->nCacheBucket ); for(pp=&pTab->aCache[h]; *pp!=pLast; pp=&((*pp)->pHashNext)); *pp = pLast->pHashNext; sqlite3_free(pLast); } zonefileCacheCheck(pTab); return SQLITE_OK; } /* ** Delete all resources associated with the frame-cache for table pTab. */ static void zonefileCacheDelete(ZonefileTab *pTab){ ZonefileFrame *p; ZonefileFrame *pNext; for(p=pTab->pCacheFirst; p; p=pNext){ pNext = p->pLruNext; sqlite3_free(p); } sqlite3_free(pTab->aCache); } static int zonefileValueReadCache(sqlite3_context *pCtx, ZonefileCsr *pCsr){ int rc = SQLITE_OK; ZonefileTab *pTab = (ZonefileTab*)pCsr->base.pVtab; ZonefileFrame *pFrame = 0; i64 iFile = sqlite3_column_int64(pCsr->pSelect, 1); |
︙ | ︙ | |||
2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 | ZonefileFrame *p = 0; int nOut = pCmpMethod->xUncompressSize(pCmp, pFrame->aBuf, pFrame->nBuf); p = (ZonefileFrame*)sqlite3_malloc(nOut + sizeof(ZonefileFrame)); if( p==0 ){ rc = SQLITE_NOMEM; }else{ p->aBuf = (u8*)&p[1]; p->nBuf = nOut; p->iFrameOff = iFrameOff; p->iFileid = iFile; rc = pCmpMethod->xUncompress( pCmp, p->aBuf, p->nBuf, pFrame->aBuf, pFrame->nBuf ); sqlite3_free(pFrame); pFrame = p; } } if( rc!=SQLITE_OK ){ sqlite3_free(pFrame); pFrame = 0; } zonefileReleaseFile(pCsr); zonefileFileClose(pFd); zonefileCodecDestroy(pCodec); if( pCmpMethod ) pCmpMethod->xClose(pCmp); if( zErr ){ assert( rc!=SQLITE_OK ); sqlite3_result_error(pCtx, zErr, -1); sqlite3_free(zErr); } } if( pFrame ){ assert( rc==SQLITE_OK ); sqlite3_result_blob(pCtx, &pFrame->aBuf[iKeyOff], nKeySz, SQLITE_TRANSIENT); | > > > > < | 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 | ZonefileFrame *p = 0; int nOut = pCmpMethod->xUncompressSize(pCmp, pFrame->aBuf, pFrame->nBuf); p = (ZonefileFrame*)sqlite3_malloc(nOut + sizeof(ZonefileFrame)); if( p==0 ){ rc = SQLITE_NOMEM; }else{ memset(p, 0, sizeof(ZonefileFrame)); p->aBuf = (u8*)&p[1]; p->nBuf = nOut; p->iFrameOff = iFrameOff; p->iFileid = iFile; rc = pCmpMethod->xUncompress( pCmp, p->aBuf, p->nBuf, pFrame->aBuf, pFrame->nBuf ); sqlite3_free(pFrame); pFrame = p; } } if( rc!=SQLITE_OK ){ sqlite3_free(pFrame); pFrame = 0; }else{ rc = zonefileCacheStore(pTab, pFrame); if( rc!=SQLITE_OK ) pFrame = 0; } zonefileReleaseFile(pCsr); zonefileFileClose(pFd); zonefileCodecDestroy(pCodec); if( pCmpMethod ) pCmpMethod->xClose(pCmp); if( zErr ){ assert( rc!=SQLITE_OK ); sqlite3_result_error(pCtx, zErr, -1); sqlite3_free(zErr); } } if( pFrame ){ assert( rc==SQLITE_OK ); sqlite3_result_blob(pCtx, &pFrame->aBuf[iKeyOff], nKeySz, SQLITE_TRANSIENT); } return rc; } /* ** zonefile virtual table module xColumn method. |
︙ | ︙ | |||
2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 | } sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pSelect, iCol)); break; } } return rc; } /* ** zonefile virtual table module xRowid method. */ static int zonefileRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ ZonefileCsr *pCsr = (ZonefileCsr*)cur; *pRowid = sqlite3_column_int64(pCsr->pSelect, 0); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 | } sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pSelect, iCol)); break; } } return rc; } /* ** zonefile virtual table module xDisconnect method. */ static int zonefileDisconnect(sqlite3_vtab *pVtab){ ZonefileTab *pTab = (ZonefileTab*)pVtab; zonefileCacheDelete(pTab); sqlite3_finalize(pTab->pIdToName); sqlite3_free(pTab); return SQLITE_OK; } /* ** zonefile virtual table module xDestroy method. */ static int zonefileDestroy(sqlite3_vtab *pVtab){ ZonefileTab *pTab = (ZonefileTab*)pVtab; int rc = SQLITE_OK; char *zSql = sqlite3_mprintf( "DROP TABLE IF EXISTS %Q.'%q_shadow_idx';" "DROP TABLE IF EXISTS %Q.'%q_shadow_file';" "DROP TABLE IF EXISTS %Q.'%q_shadow_frame';" "DROP TABLE IF EXISTS %Q.'%q_files';", pTab->zDb, pTab->zName, pTab->zDb, pTab->zName, pTab->zDb, pTab->zName ); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_exec(pTab->db, zSql, 0, 0, 0); sqlite3_free(zSql); } if( rc==SQLITE_OK ){ zonefileDisconnect(pVtab); } return rc; } /* ** zonefile virtual table module xRowid method. */ static int zonefileRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ ZonefileCsr *pCsr = (ZonefileCsr*)cur; *pRowid = sqlite3_column_int64(pCsr->pSelect, 0); |
︙ | ︙ |
Changes to ext/zonefile/zonefile1.test.
︙ | ︙ | |||
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | ) SELECT zonefile_write('test.zonefile', 'bb', json_group_object(n,v)) FROM p; } {1 {compressor "zstd_global_dict" may not be used to compress the zonefile index}} } # puts $COMPRESSION_METHODS set extra_header 0 foreach cmp $COMPRESSION_METHODS { foreach cmpidx $COMPRESSION_METHODS { if {$cmpidx == "zstd_global_dict"} continue reset_db load_static_extension db zonefile set tn "$cmp/$cmpidx" set extra_header [expr {$extra_header ? 0 : 100}] | > > | < > > > > | 104 105 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 134 135 136 137 138 139 140 | ) SELECT zonefile_write('test.zonefile', 'bb', json_group_object(n,v)) FROM p; } {1 {compressor "zstd_global_dict" may not be used to compress the zonefile index}} } # puts $COMPRESSION_METHODS set extra_header 0 set cachesize 0 foreach cmp $COMPRESSION_METHODS { foreach cmpidx $COMPRESSION_METHODS { if {$cmpidx == "zstd_global_dict"} continue reset_db load_static_extension db zonefile set tn "$cmp/$cmpidx" set extra_header [expr {$extra_header ? 0 : 100}] set cachesize [expr {$cachesize ? 0 : 10}] do_execsql_test 2.$tn.0.1 { CREATE TABLE zz( k INTEGER PRIMARY KEY, frame INTEGER DEFAULT -1, idx INTEGER DEFAULT -1, v BLOB ); CREATE TABLE rt(k INTEGER PRIMARY KEY, v BLOB); } do_execsql_test 2.$tn.0.2 " CREATE VIRTUAL TABLE zone USING zonefile(cachesize = $cachesize) " {} set nMinByte 0 set nMaxByte 444 foreach {zonefile lKey} { test1.zonefile {195 1238 298 405 297} test2.zonefile {124 1624 82 1929} test3.zonefile {932 683 1751 410 41} |
︙ | ︙ |