pcachetrace.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. ** 2023-06-21
  3. **
  4. ** The author disclaims copyright to this source code. In place of
  5. ** a legal notice, here is a blessing:
  6. **
  7. ** May you do good and not evil.
  8. ** May you find forgiveness for yourself and forgive others.
  9. ** May you share freely, never taking more than you give.
  10. **
  11. *************************************************************************
  12. **
  13. ** This file implements an extension that uses the SQLITE_CONFIG_PCACHE2
  14. ** mechanism to add a tracing layer on top of pluggable page cache of
  15. ** SQLite. If this extension is registered prior to sqlite3_initialize(),
  16. ** it will cause all page cache activities to be logged on standard output,
  17. ** or to some other FILE specified by the initializer.
  18. **
  19. ** This file needs to be compiled into the application that uses it.
  20. **
  21. ** This extension is used to implement the --pcachetrace option of the
  22. ** command-line shell.
  23. */
  24. #include <assert.h>
  25. #include <string.h>
  26. #include <stdio.h>
  27. /* The original page cache routines */
  28. static sqlite3_pcache_methods2 pcacheBase;
  29. static FILE *pcachetraceOut;
  30. /* Methods that trace pcache activity */
  31. static int pcachetraceInit(void *pArg){
  32. int nRes;
  33. if( pcachetraceOut ){
  34. fprintf(pcachetraceOut, "PCACHETRACE: xInit(%p)\n", pArg);
  35. }
  36. nRes = pcacheBase.xInit(pArg);
  37. if( pcachetraceOut ){
  38. fprintf(pcachetraceOut, "PCACHETRACE: xInit(%p) -> %d\n", pArg, nRes);
  39. }
  40. return nRes;
  41. }
  42. static void pcachetraceShutdown(void *pArg){
  43. if( pcachetraceOut ){
  44. fprintf(pcachetraceOut, "PCACHETRACE: xShutdown(%p)\n", pArg);
  45. }
  46. pcacheBase.xShutdown(pArg);
  47. }
  48. static sqlite3_pcache *pcachetraceCreate(int szPage, int szExtra, int bPurge){
  49. sqlite3_pcache *pRes;
  50. if( pcachetraceOut ){
  51. fprintf(pcachetraceOut, "PCACHETRACE: xCreate(%d,%d,%d)\n",
  52. szPage, szExtra, bPurge);
  53. }
  54. pRes = pcacheBase.xCreate(szPage, szExtra, bPurge);
  55. if( pcachetraceOut ){
  56. fprintf(pcachetraceOut, "PCACHETRACE: xCreate(%d,%d,%d) -> %p\n",
  57. szPage, szExtra, bPurge, pRes);
  58. }
  59. return pRes;
  60. }
  61. static void pcachetraceCachesize(sqlite3_pcache *p, int nCachesize){
  62. if( pcachetraceOut ){
  63. fprintf(pcachetraceOut, "PCACHETRACE: xCachesize(%p, %d)\n", p, nCachesize);
  64. }
  65. pcacheBase.xCachesize(p, nCachesize);
  66. }
  67. static int pcachetracePagecount(sqlite3_pcache *p){
  68. int nRes;
  69. if( pcachetraceOut ){
  70. fprintf(pcachetraceOut, "PCACHETRACE: xPagecount(%p)\n", p);
  71. }
  72. nRes = pcacheBase.xPagecount(p);
  73. if( pcachetraceOut ){
  74. fprintf(pcachetraceOut, "PCACHETRACE: xPagecount(%p) -> %d\n", p, nRes);
  75. }
  76. return nRes;
  77. }
  78. static sqlite3_pcache_page *pcachetraceFetch(
  79. sqlite3_pcache *p,
  80. unsigned key,
  81. int crFg
  82. ){
  83. sqlite3_pcache_page *pRes;
  84. if( pcachetraceOut ){
  85. fprintf(pcachetraceOut, "PCACHETRACE: xFetch(%p,%u,%d)\n", p, key, crFg);
  86. }
  87. pRes = pcacheBase.xFetch(p, key, crFg);
  88. if( pcachetraceOut ){
  89. fprintf(pcachetraceOut, "PCACHETRACE: xFetch(%p,%u,%d) -> %p\n",
  90. p, key, crFg, pRes);
  91. }
  92. return pRes;
  93. }
  94. static void pcachetraceUnpin(
  95. sqlite3_pcache *p,
  96. sqlite3_pcache_page *pPg,
  97. int bDiscard
  98. ){
  99. if( pcachetraceOut ){
  100. fprintf(pcachetraceOut, "PCACHETRACE: xUnpin(%p, %p, %d)\n",
  101. p, pPg, bDiscard);
  102. }
  103. pcacheBase.xUnpin(p, pPg, bDiscard);
  104. }
  105. static void pcachetraceRekey(
  106. sqlite3_pcache *p,
  107. sqlite3_pcache_page *pPg,
  108. unsigned oldKey,
  109. unsigned newKey
  110. ){
  111. if( pcachetraceOut ){
  112. fprintf(pcachetraceOut, "PCACHETRACE: xRekey(%p, %p, %u, %u)\n",
  113. p, pPg, oldKey, newKey);
  114. }
  115. pcacheBase.xRekey(p, pPg, oldKey, newKey);
  116. }
  117. static void pcachetraceTruncate(sqlite3_pcache *p, unsigned n){
  118. if( pcachetraceOut ){
  119. fprintf(pcachetraceOut, "PCACHETRACE: xTruncate(%p, %u)\n", p, n);
  120. }
  121. pcacheBase.xTruncate(p, n);
  122. }
  123. static void pcachetraceDestroy(sqlite3_pcache *p){
  124. if( pcachetraceOut ){
  125. fprintf(pcachetraceOut, "PCACHETRACE: xDestroy(%p)\n", p);
  126. }
  127. pcacheBase.xDestroy(p);
  128. }
  129. static void pcachetraceShrink(sqlite3_pcache *p){
  130. if( pcachetraceOut ){
  131. fprintf(pcachetraceOut, "PCACHETRACE: xShrink(%p)\n", p);
  132. }
  133. pcacheBase.xShrink(p);
  134. }
  135. /* The substitute pcache methods */
  136. static sqlite3_pcache_methods2 ersaztPcacheMethods = {
  137. 0,
  138. 0,
  139. pcachetraceInit,
  140. pcachetraceShutdown,
  141. pcachetraceCreate,
  142. pcachetraceCachesize,
  143. pcachetracePagecount,
  144. pcachetraceFetch,
  145. pcachetraceUnpin,
  146. pcachetraceRekey,
  147. pcachetraceTruncate,
  148. pcachetraceDestroy,
  149. pcachetraceShrink
  150. };
  151. /* Begin tracing memory allocations to out. */
  152. int sqlite3PcacheTraceActivate(FILE *out){
  153. int rc = SQLITE_OK;
  154. if( pcacheBase.xFetch==0 ){
  155. rc = sqlite3_config(SQLITE_CONFIG_GETPCACHE2, &pcacheBase);
  156. if( rc==SQLITE_OK ){
  157. rc = sqlite3_config(SQLITE_CONFIG_PCACHE2, &ersaztPcacheMethods);
  158. }
  159. }
  160. pcachetraceOut = out;
  161. return rc;
  162. }
  163. /* Deactivate memory tracing */
  164. int sqlite3PcacheTraceDeactivate(void){
  165. int rc = SQLITE_OK;
  166. if( pcacheBase.xFetch!=0 ){
  167. rc = sqlite3_config(SQLITE_CONFIG_PCACHE2, &pcacheBase);
  168. if( rc==SQLITE_OK ){
  169. memset(&pcacheBase, 0, sizeof(pcacheBase));
  170. }
  171. }
  172. pcachetraceOut = 0;
  173. return rc;
  174. }