mem4.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. ** 2007 August 14
  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. ** This file contains the C functions that implement a memory
  13. ** allocation subsystem for use by SQLite.
  14. **
  15. ** $Id: mem4.c,v 1.1 2007/11/29 18:36:49 drh Exp $
  16. */
  17. /*
  18. ** This version of the memory allocator attempts to obtain memory
  19. ** from mmap() if the size of the allocation is close to the size
  20. ** of a virtual memory page. If the size of the allocation is different
  21. ** from the virtual memory page size, then ordinary malloc() is used.
  22. ** Ordinary malloc is also used if space allocated to mmap() is
  23. ** exhausted.
  24. **
  25. ** Enable this memory allocation by compiling with -DSQLITE_MMAP_HEAP_SIZE=nnn
  26. ** where nnn is the maximum number of bytes of mmap-ed memory you want
  27. ** to support. This module may choose to use less memory than requested.
  28. **
  29. */
  30. #if defined(SQLITE_MMAP_HEAP_SIZE)
  31. #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE)
  32. # error cannot use SQLITE_MMAP_HEAP_SIZE with either SQLITE_MEMDEBUG \
  33. or SQLITE_MEMORY_SIZE
  34. #endif
  35. /*
  36. ** This is a test version of the memory allocator that attempts to
  37. ** use mmap() and madvise() for allocations and frees of approximately
  38. ** the virtual memory page size.
  39. */
  40. #include <sys/types.h>
  41. #include <sys/mman.h>
  42. #include <errno.h>
  43. #include "sqliteInt.h"
  44. #include <unistd.h>
  45. /*
  46. ** All of the static variables used by this module are collected
  47. ** into a single structure named "mem". This is to keep the
  48. ** static variables organized and to reduce namespace pollution
  49. ** when this module is combined with other in the amalgamation.
  50. */
  51. static struct {
  52. /*
  53. ** The alarm callback and its arguments. The mem.mutex lock will
  54. ** be held while the callback is running. Recursive calls into
  55. ** the memory subsystem are allowed, but no new callbacks will be
  56. ** issued. The alarmBusy variable is set to prevent recursive
  57. ** callbacks.
  58. */
  59. sqlite3_int64 alarmThreshold;
  60. void (*alarmCallback)(void*, sqlite3_int64,int);
  61. void *alarmArg;
  62. int alarmBusy;
  63. /*
  64. ** Mutex to control access to the memory allocation subsystem.
  65. */
  66. sqlite3_mutex *mutex;
  67. /*
  68. ** Current allocation and high-water mark.
  69. */
  70. sqlite3_int64 nowUsed;
  71. sqlite3_int64 mxUsed;
  72. /*
  73. ** Current allocation and high-water marks for mmap allocated memory.
  74. */
  75. sqlite3_int64 nowUsedMMap;
  76. sqlite3_int64 mxUsedMMap;
  77. /*
  78. ** Size of a single mmap page. Obtained from sysconf().
  79. */
  80. int szPage;
  81. int mnPage;
  82. /*
  83. ** The number of available mmap pages.
  84. */
  85. int nPage;
  86. /*
  87. ** Index of the first free page. 0 means no pages have been freed.
  88. */
  89. int firstFree;
  90. /* First unused page on the top of the heap.
  91. */
  92. int firstUnused;
  93. /*
  94. ** Bulk memory obtained from from mmap().
  95. */
  96. char *mmapHeap; /* first byte of the heap */
  97. } mem;
  98. /*
  99. ** Enter the mutex mem.mutex. Allocate it if it is not already allocated.
  100. ** The mmap() region is initialized the first time this routine is called.
  101. */
  102. static void memsys4Enter(void){
  103. if( mem.mutex==0 ){
  104. mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
  105. }
  106. sqlite3_mutex_enter(mem.mutex);
  107. }
  108. /*
  109. ** Attempt to free memory to the mmap heap. This only works if
  110. ** the pointer p is within the range of memory addresses that
  111. ** comprise the mmap heap. Return 1 if the memory was freed
  112. ** successfully. Return 0 if the pointer is out of range.
  113. */
  114. static int mmapFree(void *p){
  115. char *z;
  116. int idx, *a;
  117. if( mem.mmapHeap==MAP_FAILED || mem.nPage==0 ){
  118. return 0;
  119. }
  120. z = (char*)p;
  121. idx = (z - mem.mmapHeap)/mem.szPage;
  122. if( idx<1 || idx>=mem.nPage ){
  123. return 0;
  124. }
  125. a = (int*)mem.mmapHeap;
  126. a[idx] = a[mem.firstFree];
  127. mem.firstFree = idx;
  128. mem.nowUsedMMap -= mem.szPage;
  129. madvise(p, mem.szPage, MADV_DONTNEED);
  130. return 1;
  131. }
  132. /*
  133. ** Attempt to allocate nBytes from the mmap heap. Return a pointer
  134. ** to the allocated page. Or, return NULL if the allocation fails.
  135. **
  136. ** The allocation will fail if nBytes is not the right size.
  137. ** Or, the allocation will fail if the mmap heap has been exhausted.
  138. */
  139. static void *mmapAlloc(int nBytes){
  140. int idx = 0;
  141. if( nBytes>mem.szPage || nBytes<mem.mnPage ){
  142. return 0;
  143. }
  144. if( mem.nPage==0 ){
  145. mem.szPage = sysconf(_SC_PAGE_SIZE);
  146. mem.mnPage = mem.szPage - mem.szPage/10;
  147. mem.nPage = SQLITE_MMAP_HEAP_SIZE/mem.szPage;
  148. if( mem.nPage * sizeof(int) > mem.szPage ){
  149. mem.nPage = mem.szPage/sizeof(int);
  150. }
  151. mem.mmapHeap = mmap(0, mem.szPage*mem.nPage, PROT_WRITE|PROT_READ,
  152. MAP_ANONYMOUS|MAP_SHARED, -1, 0);
  153. if( mem.mmapHeap==MAP_FAILED ){
  154. mem.firstUnused = errno;
  155. }else{
  156. mem.firstUnused = 1;
  157. mem.nowUsedMMap = mem.szPage;
  158. }
  159. }
  160. if( mem.mmapHeap==MAP_FAILED ){
  161. return 0;
  162. }
  163. if( mem.firstFree ){
  164. int idx = mem.firstFree;
  165. int *a = (int*)mem.mmapHeap;
  166. mem.firstFree = a[idx];
  167. }else if( mem.firstUnused<mem.nPage ){
  168. idx = mem.firstUnused++;
  169. }
  170. if( idx ){
  171. mem.nowUsedMMap += mem.szPage;
  172. if( mem.nowUsedMMap>mem.mxUsedMMap ){
  173. mem.mxUsedMMap = mem.nowUsedMMap;
  174. }
  175. return (void*)&mem.mmapHeap[idx*mem.szPage];
  176. }else{
  177. return 0;
  178. }
  179. }
  180. /*
  181. ** Release the mmap-ed memory region if it is currently allocated and
  182. ** is not in use.
  183. */
  184. static void mmapUnmap(void){
  185. if( mem.mmapHeap==MAP_FAILED ) return;
  186. if( mem.nPage==0 ) return;
  187. if( mem.nowUsedMMap>mem.szPage ) return;
  188. munmap(mem.mmapHeap, mem.nPage*mem.szPage);
  189. mem.nowUsedMMap = 0;
  190. mem.nPage = 0;
  191. }
  192. /*
  193. ** Return the amount of memory currently checked out.
  194. */
  195. sqlite3_int64 sqlite3_memory_used(void){
  196. sqlite3_int64 n;
  197. memsys4Enter();
  198. n = mem.nowUsed + mem.nowUsedMMap;
  199. sqlite3_mutex_leave(mem.mutex);
  200. return n;
  201. }
  202. /*
  203. ** Return the maximum amount of memory that has ever been
  204. ** checked out since either the beginning of this process
  205. ** or since the most recent reset.
  206. */
  207. sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
  208. sqlite3_int64 n;
  209. memsys4Enter();
  210. n = mem.mxUsed + mem.mxUsedMMap;
  211. if( resetFlag ){
  212. mem.mxUsed = mem.nowUsed;
  213. mem.mxUsedMMap = mem.nowUsedMMap;
  214. }
  215. sqlite3_mutex_leave(mem.mutex);
  216. return n;
  217. }
  218. /*
  219. ** Change the alarm callback
  220. */
  221. int sqlite3_memory_alarm(
  222. void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
  223. void *pArg,
  224. sqlite3_int64 iThreshold
  225. ){
  226. memsys4Enter();
  227. mem.alarmCallback = xCallback;
  228. mem.alarmArg = pArg;
  229. mem.alarmThreshold = iThreshold;
  230. sqlite3_mutex_leave(mem.mutex);
  231. return SQLITE_OK;
  232. }
  233. /*
  234. ** Trigger the alarm
  235. */
  236. static void sqlite3MemsysAlarm(int nByte){
  237. void (*xCallback)(void*,sqlite3_int64,int);
  238. sqlite3_int64 nowUsed;
  239. void *pArg;
  240. if( mem.alarmCallback==0 || mem.alarmBusy ) return;
  241. mem.alarmBusy = 1;
  242. xCallback = mem.alarmCallback;
  243. nowUsed = mem.nowUsed;
  244. pArg = mem.alarmArg;
  245. sqlite3_mutex_leave(mem.mutex);
  246. xCallback(pArg, nowUsed, nByte);
  247. sqlite3_mutex_enter(mem.mutex);
  248. mem.alarmBusy = 0;
  249. }
  250. /*
  251. ** Allocate nBytes of memory
  252. */
  253. static void *memsys4Malloc(int nBytes){
  254. sqlite3_int64 *p = 0;
  255. if( mem.alarmCallback!=0
  256. && mem.nowUsed+mem.nowUsedMMap+nBytes>=mem.alarmThreshold ){
  257. sqlite3MemsysAlarm(nBytes);
  258. }
  259. if( (p = mmapAlloc(nBytes))==0 ){
  260. p = malloc(nBytes+8);
  261. if( p==0 ){
  262. sqlite3MemsysAlarm(nBytes);
  263. p = malloc(nBytes+8);
  264. }
  265. if( p ){
  266. p[0] = nBytes;
  267. p++;
  268. mem.nowUsed += nBytes;
  269. if( mem.nowUsed>mem.mxUsed ){
  270. mem.mxUsed = mem.nowUsed;
  271. }
  272. }
  273. }
  274. return (void*)p;
  275. }
  276. /*
  277. ** Return the size of a memory allocation
  278. */
  279. static int memsys4Size(void *pPrior){
  280. char *z = (char*)pPrior;
  281. int idx = mem.nPage ? (z - mem.mmapHeap)/mem.szPage : 0;
  282. int nByte;
  283. if( idx>=1 && idx<mem.nPage ){
  284. nByte = mem.szPage;
  285. }else{
  286. sqlite3_int64 *p = pPrior;
  287. p--;
  288. nByte = (int)*p;
  289. }
  290. return nByte;
  291. }
  292. /*
  293. ** Free memory.
  294. */
  295. static void memsys4Free(void *pPrior){
  296. sqlite3_int64 *p;
  297. int nByte;
  298. if( mmapFree(pPrior)==0 ){
  299. p = pPrior;
  300. p--;
  301. nByte = (int)*p;
  302. mem.nowUsed -= nByte;
  303. free(p);
  304. if( mem.nowUsed==0 ){
  305. mmapUnmap();
  306. }
  307. }
  308. }
  309. /*
  310. ** Allocate nBytes of memory
  311. */
  312. void *sqlite3_malloc(int nBytes){
  313. sqlite3_int64 *p = 0;
  314. if( nBytes>0 ){
  315. memsys4Enter();
  316. p = memsys4Malloc(nBytes);
  317. sqlite3_mutex_leave(mem.mutex);
  318. }
  319. return (void*)p;
  320. }
  321. /*
  322. ** Free memory.
  323. */
  324. void sqlite3_free(void *pPrior){
  325. if( pPrior==0 ){
  326. return;
  327. }
  328. assert( mem.mutex!=0 );
  329. sqlite3_mutex_enter(mem.mutex);
  330. memsys4Free(pPrior);
  331. sqlite3_mutex_leave(mem.mutex);
  332. }
  333. /*
  334. ** Change the size of an existing memory allocation
  335. */
  336. void *sqlite3_realloc(void *pPrior, int nBytes){
  337. int nOld;
  338. sqlite3_int64 *p;
  339. if( pPrior==0 ){
  340. return sqlite3_malloc(nBytes);
  341. }
  342. if( nBytes<=0 ){
  343. sqlite3_free(pPrior);
  344. return 0;
  345. }
  346. nOld = memsys4Size(pPrior);
  347. if( nBytes<=nOld && nBytes>=nOld-128 ){
  348. return pPrior;
  349. }
  350. assert( mem.mutex!=0 );
  351. sqlite3_mutex_enter(mem.mutex);
  352. p = memsys4Malloc(nBytes);
  353. if( p ){
  354. if( nOld<nBytes ){
  355. memcpy(p, pPrior, nOld);
  356. }else{
  357. memcpy(p, pPrior, nBytes);
  358. }
  359. memsys4Free(pPrior);
  360. }
  361. assert( mem.mutex!=0 );
  362. sqlite3_mutex_leave(mem.mutex);
  363. return (void*)p;
  364. }
  365. #endif /* !SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */