mirror of
				https://github.com/tursodatabase/libsql.git
				synced 2025-11-04 05:58:57 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			180 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			180 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
** 2023-06-21
 | 
						|
**
 | 
						|
** The author disclaims copyright to this source code.  In place of
 | 
						|
** a legal notice, here is a blessing:
 | 
						|
**
 | 
						|
**    May you do good and not evil.
 | 
						|
**    May you find forgiveness for yourself and forgive others.
 | 
						|
**    May you share freely, never taking more than you give.
 | 
						|
**
 | 
						|
*************************************************************************
 | 
						|
**
 | 
						|
** This file implements an extension that uses the SQLITE_CONFIG_PCACHE2
 | 
						|
** mechanism to add a tracing layer on top of pluggable page cache of
 | 
						|
** SQLite.  If this extension is registered prior to sqlite3_initialize(),
 | 
						|
** it will cause all page cache activities to be logged on standard output,
 | 
						|
** or to some other FILE specified by the initializer.
 | 
						|
**
 | 
						|
** This file needs to be compiled into the application that uses it.
 | 
						|
**
 | 
						|
** This extension is used to implement the --pcachetrace option of the
 | 
						|
** command-line shell.
 | 
						|
*/
 | 
						|
#include <assert.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
/* The original page cache routines */
 | 
						|
static sqlite3_pcache_methods2 pcacheBase;
 | 
						|
static FILE *pcachetraceOut;
 | 
						|
 | 
						|
/* Methods that trace pcache activity */
 | 
						|
static int pcachetraceInit(void *pArg){
 | 
						|
  int nRes;
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xInit(%p)\n", pArg);
 | 
						|
  }
 | 
						|
  nRes = pcacheBase.xInit(pArg);
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xInit(%p) -> %d\n", pArg, nRes);
 | 
						|
  }
 | 
						|
  return nRes;
 | 
						|
}
 | 
						|
static void pcachetraceShutdown(void *pArg){
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xShutdown(%p)\n", pArg);
 | 
						|
  }
 | 
						|
  pcacheBase.xShutdown(pArg);
 | 
						|
}
 | 
						|
static sqlite3_pcache *pcachetraceCreate(int szPage, int szExtra, int bPurge){
 | 
						|
  sqlite3_pcache *pRes;
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xCreate(%d,%d,%d)\n",
 | 
						|
            szPage, szExtra, bPurge);
 | 
						|
  }
 | 
						|
  pRes = pcacheBase.xCreate(szPage, szExtra, bPurge);
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xCreate(%d,%d,%d) -> %p\n",
 | 
						|
            szPage, szExtra, bPurge, pRes);
 | 
						|
  }
 | 
						|
  return pRes;
 | 
						|
}
 | 
						|
static void pcachetraceCachesize(sqlite3_pcache *p, int nCachesize){
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xCachesize(%p, %d)\n", p, nCachesize);
 | 
						|
  }
 | 
						|
  pcacheBase.xCachesize(p, nCachesize);
 | 
						|
}
 | 
						|
static int pcachetracePagecount(sqlite3_pcache *p){
 | 
						|
  int nRes;
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xPagecount(%p)\n", p);
 | 
						|
  }
 | 
						|
  nRes = pcacheBase.xPagecount(p);
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xPagecount(%p) -> %d\n", p, nRes);
 | 
						|
  }
 | 
						|
  return nRes;
 | 
						|
}
 | 
						|
static sqlite3_pcache_page *pcachetraceFetch(
 | 
						|
  sqlite3_pcache *p,
 | 
						|
  unsigned key,
 | 
						|
  int crFg
 | 
						|
){
 | 
						|
  sqlite3_pcache_page *pRes;
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xFetch(%p,%u,%d)\n", p, key, crFg);
 | 
						|
  }
 | 
						|
  pRes = pcacheBase.xFetch(p, key, crFg);
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xFetch(%p,%u,%d) -> %p\n",
 | 
						|
            p, key, crFg, pRes);
 | 
						|
  }
 | 
						|
  return pRes;
 | 
						|
}
 | 
						|
static void pcachetraceUnpin(
 | 
						|
  sqlite3_pcache *p,
 | 
						|
  sqlite3_pcache_page *pPg,
 | 
						|
  int bDiscard
 | 
						|
){
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xUnpin(%p, %p, %d)\n",
 | 
						|
            p, pPg, bDiscard);
 | 
						|
  }
 | 
						|
  pcacheBase.xUnpin(p, pPg, bDiscard);
 | 
						|
}
 | 
						|
static void pcachetraceRekey(
 | 
						|
  sqlite3_pcache *p,
 | 
						|
  sqlite3_pcache_page *pPg,
 | 
						|
  unsigned oldKey,
 | 
						|
  unsigned newKey
 | 
						|
){
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xRekey(%p, %p, %u, %u)\n",
 | 
						|
        p, pPg, oldKey, newKey);
 | 
						|
  }
 | 
						|
  pcacheBase.xRekey(p, pPg, oldKey, newKey);
 | 
						|
}
 | 
						|
static void pcachetraceTruncate(sqlite3_pcache *p, unsigned n){
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xTruncate(%p, %u)\n", p, n);
 | 
						|
  }
 | 
						|
  pcacheBase.xTruncate(p, n);
 | 
						|
}
 | 
						|
static void pcachetraceDestroy(sqlite3_pcache *p){
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xDestroy(%p)\n", p);
 | 
						|
  }
 | 
						|
  pcacheBase.xDestroy(p);
 | 
						|
}
 | 
						|
static void pcachetraceShrink(sqlite3_pcache *p){
 | 
						|
  if( pcachetraceOut ){
 | 
						|
    fprintf(pcachetraceOut, "PCACHETRACE: xShrink(%p)\n", p);
 | 
						|
  }
 | 
						|
  pcacheBase.xShrink(p);
 | 
						|
}
 | 
						|
 | 
						|
/* The substitute pcache methods */
 | 
						|
static sqlite3_pcache_methods2 ersaztPcacheMethods = {
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  pcachetraceInit,
 | 
						|
  pcachetraceShutdown,
 | 
						|
  pcachetraceCreate,
 | 
						|
  pcachetraceCachesize,
 | 
						|
  pcachetracePagecount,
 | 
						|
  pcachetraceFetch,
 | 
						|
  pcachetraceUnpin,
 | 
						|
  pcachetraceRekey,
 | 
						|
  pcachetraceTruncate,
 | 
						|
  pcachetraceDestroy,
 | 
						|
  pcachetraceShrink
 | 
						|
};
 | 
						|
 | 
						|
/* Begin tracing memory allocations to out. */
 | 
						|
int sqlite3PcacheTraceActivate(FILE *out){
 | 
						|
  int rc = SQLITE_OK;
 | 
						|
  if( pcacheBase.xFetch==0 ){
 | 
						|
    rc = sqlite3_config(SQLITE_CONFIG_GETPCACHE2, &pcacheBase);
 | 
						|
    if( rc==SQLITE_OK ){
 | 
						|
      rc = sqlite3_config(SQLITE_CONFIG_PCACHE2, &ersaztPcacheMethods);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  pcachetraceOut = out;
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
/* Deactivate memory tracing */
 | 
						|
int sqlite3PcacheTraceDeactivate(void){
 | 
						|
  int rc = SQLITE_OK;
 | 
						|
  if( pcacheBase.xFetch!=0 ){
 | 
						|
    rc = sqlite3_config(SQLITE_CONFIG_PCACHE2, &pcacheBase);
 | 
						|
    if( rc==SQLITE_OK ){
 | 
						|
      memset(&pcacheBase, 0, sizeof(pcacheBase));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  pcachetraceOut = 0;
 | 
						|
  return rc;
 | 
						|
}
 |