lsm_file.c 97 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312
  1. /*
  2. ** 2011-08-26
  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. ** NORMAL DATABASE FILE FORMAT
  14. **
  15. ** The following database file format concepts are used by the code in
  16. ** this file to read and write the database file.
  17. **
  18. ** Pages:
  19. **
  20. ** A database file is divided into pages. The first 8KB of the file consists
  21. ** of two 4KB meta-pages. The meta-page size is not configurable. The
  22. ** remainder of the file is made up of database pages. The default database
  23. ** page size is 4KB. Database pages are aligned to page-size boundaries,
  24. ** so if the database page size is larger than 8KB there is a gap between
  25. ** the end of the meta pages and the start of the database pages.
  26. **
  27. ** Database pages are numbered based on their position in the file. Page N
  28. ** begins at byte offset ((N-1)*pgsz). This means that page 1 does not
  29. ** exist - since it would always overlap with the meta pages. If the
  30. ** page-size is (say) 512 bytes, then the first usable page in the database
  31. ** is page 33.
  32. **
  33. ** It is assumed that the first two meta pages and the data that follows
  34. ** them are located on different disk sectors. So that if a power failure
  35. ** while writing to a meta page there is no risk of damage to the other
  36. ** meta page or any other part of the database file. TODO: This may need
  37. ** to be revisited.
  38. **
  39. ** Blocks:
  40. **
  41. ** The database file is also divided into blocks. The default block size is
  42. ** 1MB. When writing to the database file, an attempt is made to write data
  43. ** in contiguous block-sized chunks.
  44. **
  45. ** The first and last page on each block are special in that they are 4
  46. ** bytes smaller than all other pages. This is because the last four bytes
  47. ** of space on the first and last pages of each block are reserved for
  48. ** pointers to other blocks (i.e. a 32-bit block number).
  49. **
  50. ** Runs:
  51. **
  52. ** A run is a sequence of pages that the upper layer uses to store a
  53. ** sorted array of database keys (and accompanying data - values, FC
  54. ** pointers and so on). Given a page within a run, it is possible to
  55. ** navigate to the next page in the run as follows:
  56. **
  57. ** a) if the current page is not the last in a block, the next page
  58. ** in the run is located immediately after the current page, OR
  59. **
  60. ** b) if the current page is the last page in a block, the next page
  61. ** in the run is the first page on the block identified by the
  62. ** block pointer stored in the last 4 bytes of the current block.
  63. **
  64. ** It is possible to navigate to the previous page in a similar fashion,
  65. ** using the block pointer embedded in the last 4 bytes of the first page
  66. ** of each block as required.
  67. **
  68. ** The upper layer is responsible for identifying by page number the
  69. ** first and last page of any run that it needs to navigate - there are
  70. ** no "end-of-run" markers stored or identified by this layer. This is
  71. ** necessary as clients reading different database snapshots may access
  72. ** different subsets of a run.
  73. **
  74. ** THE LOG FILE
  75. **
  76. ** This file opens and closes the log file. But it does not contain any
  77. ** logic related to the log file format. Instead, it exports the following
  78. ** functions that are used by the code in lsm_log.c to read and write the
  79. ** log file:
  80. **
  81. ** lsmFsOpenLog
  82. ** lsmFsWriteLog
  83. ** lsmFsSyncLog
  84. ** lsmFsReadLog
  85. ** lsmFsTruncateLog
  86. ** lsmFsCloseAndDeleteLog
  87. **
  88. ** COMPRESSED DATABASE FILE FORMAT
  89. **
  90. ** The compressed database file format is very similar to the normal format.
  91. ** The file still begins with two 4KB meta-pages (which are never compressed).
  92. ** It is still divided into blocks.
  93. **
  94. ** The first and last four bytes of each block are reserved for 32-bit
  95. ** pointer values. Similar to the way four bytes are carved from the end of
  96. ** the first and last page of each block in uncompressed databases. From
  97. ** the point of view of the upper layer, all pages are the same size - this
  98. ** is different from the uncompressed format where the first and last pages
  99. ** on each block are 4 bytes smaller than the others.
  100. **
  101. ** Pages are stored in variable length compressed form, as follows:
  102. **
  103. ** * 3-byte size field containing the size of the compressed page image
  104. ** in bytes. The most significant bit of each byte of the size field
  105. ** is always set. The remaining 7 bits are used to store a 21-bit
  106. ** integer value (in big-endian order - the first byte in the field
  107. ** contains the most significant 7 bits). Since the maximum allowed
  108. ** size of a compressed page image is (2^17 - 1) bytes, there are
  109. ** actually 4 unused bits in the size field.
  110. **
  111. ** In other words, if the size of the compressed page image is nSz,
  112. ** the header can be serialized as follows:
  113. **
  114. ** u8 aHdr[3]
  115. ** aHdr[0] = 0x80 | (u8)(nSz >> 14);
  116. ** aHdr[1] = 0x80 | (u8)(nSz >> 7);
  117. ** aHdr[2] = 0x80 | (u8)(nSz >> 0);
  118. **
  119. ** * Compressed page image.
  120. **
  121. ** * A second copy of the 3-byte record header.
  122. **
  123. ** A page number is a byte offset into the database file. So the smallest
  124. ** possible page number is 8192 (immediately after the two meta-pages).
  125. ** The first and root page of a segment are identified by a page number
  126. ** corresponding to the byte offset of the first byte in the corresponding
  127. ** page record. The last page of a segment is identified by the byte offset
  128. ** of the last byte in its record.
  129. **
  130. ** Unlike uncompressed pages, compressed page records may span blocks.
  131. **
  132. ** Sometimes, in order to avoid touching sectors that contain synced data
  133. ** when writing, it is necessary to insert unused space between compressed
  134. ** page records. This can be done as follows:
  135. **
  136. ** * For less than 6 bytes of empty space, the first and last byte
  137. ** of the free space contain the total number of free bytes. For
  138. ** example:
  139. **
  140. ** Block of 4 free bytes: 0x04 0x?? 0x?? 0x04
  141. ** Block of 2 free bytes: 0x02 0x02
  142. ** A single free byte: 0x01
  143. **
  144. ** * For 6 or more bytes of empty space, a record similar to a
  145. ** compressed page record is added to the segment. A padding record
  146. ** is distinguished from a compressed page record by the most
  147. ** significant bit of the second byte of the size field, which is
  148. ** cleared instead of set.
  149. */
  150. #include "lsmInt.h"
  151. #include <sys/types.h>
  152. #include <sys/stat.h>
  153. #include <fcntl.h>
  154. /*
  155. ** File-system object. Each database connection allocates a single instance
  156. ** of the following structure. It is used for all access to the database and
  157. ** log files.
  158. **
  159. ** The database file may be accessed via two methods - using mmap() or using
  160. ** read() and write() calls. In the general case both methods are used - a
  161. ** prefix of the file is mapped into memory and the remainder accessed using
  162. ** read() and write(). This is helpful when accessing very large files (or
  163. ** files that may grow very large during the lifetime of a database
  164. ** connection) on systems with 32-bit address spaces. However, it also requires
  165. ** that this object manage two distinct types of Page objects simultaneously -
  166. ** those that carry pointers to the mapped file and those that carry arrays
  167. ** populated by read() calls.
  168. **
  169. ** pFree:
  170. ** The head of a singly-linked list that containing currently unused Page
  171. ** structures suitable for use as mmap-page handles. Connected by the
  172. ** Page.pFreeNext pointers.
  173. **
  174. ** pMapped:
  175. ** The head of a singly-linked list that contains all pages that currently
  176. ** carry pointers to the mapped region. This is used if the region is
  177. ** every remapped - the pointers carried by existing pages can be adjusted
  178. ** to account for the remapping. Connected by the Page.pMappedNext pointers.
  179. **
  180. ** pWaiting:
  181. ** When the upper layer wishes to append a new b-tree page to a segment,
  182. ** it allocates a Page object that carries a malloc'd block of memory -
  183. ** regardless of the mmap-related configuration. The page is not assigned
  184. ** a page number at first. When the upper layer has finished constructing
  185. ** the page contents, it calls lsmFsPagePersist() to assign a page number
  186. ** to it. At this point it is likely that N pages have been written to the
  187. ** segment, the (N+1)th page is still outstanding and the b-tree page is
  188. ** assigned page number (N+2). To avoid writing page (N+2) before page
  189. ** (N+1), the recently completed b-tree page is held in the singly linked
  190. ** list headed by pWaiting until page (N+1) has been written.
  191. **
  192. ** Function lsmFsFlushWaiting() is responsible for eventually writing
  193. ** waiting pages to disk.
  194. **
  195. ** apHash/nHash:
  196. ** Hash table used to store all Page objects that carry malloc'd arrays,
  197. ** except those b-tree pages that have not yet been assigned page numbers.
  198. ** Once they have been assigned page numbers - they are added to this
  199. ** hash table.
  200. **
  201. ** Hash table overflow chains are connected using the Page.pHashNext
  202. ** pointers.
  203. **
  204. ** pLruFirst, pLruLast:
  205. ** The first and last entries in a doubly-linked list of pages. This
  206. ** list contains all pages with malloc'd data that are present in the
  207. ** hash table and have a ref-count of zero.
  208. */
  209. struct FileSystem {
  210. lsm_db *pDb; /* Database handle that owns this object */
  211. lsm_env *pEnv; /* Environment pointer */
  212. char *zDb; /* Database file name */
  213. char *zLog; /* Database file name */
  214. int nMetasize; /* Size of meta pages in bytes */
  215. int nMetaRwSize; /* Read/written size of meta pages in bytes */
  216. i64 nPagesize; /* Database page-size in bytes */
  217. i64 nBlocksize; /* Database block-size in bytes */
  218. /* r/w file descriptors for both files. */
  219. LsmFile *pLsmFile; /* Used after lsm_close() to link into list */
  220. lsm_file *fdDb; /* Database file */
  221. lsm_file *fdLog; /* Log file */
  222. int szSector; /* Database file sector size */
  223. /* If this is a compressed database, a pointer to the compression methods.
  224. ** For an uncompressed database, a NULL pointer. */
  225. lsm_compress *pCompress;
  226. u8 *aIBuffer; /* Buffer to compress to */
  227. u8 *aOBuffer; /* Buffer to uncompress from */
  228. int nBuffer; /* Allocated size of above buffers in bytes */
  229. /* mmap() page related things */
  230. i64 nMapLimit; /* Maximum bytes of file to map */
  231. void *pMap; /* Current mapping of database file */
  232. i64 nMap; /* Bytes mapped at pMap */
  233. Page *pFree; /* Unused Page structures */
  234. Page *pMapped; /* List of Page structs that point to pMap */
  235. /* Page cache parameters for non-mmap() pages */
  236. int nCacheMax; /* Configured cache size (in pages) */
  237. int nCacheAlloc; /* Current cache size (in pages) */
  238. Page *pLruFirst; /* Head of the LRU list */
  239. Page *pLruLast; /* Tail of the LRU list */
  240. int nHash; /* Number of hash slots in hash table */
  241. Page **apHash; /* nHash Hash slots */
  242. Page *pWaiting; /* b-tree pages waiting to be written */
  243. /* Statistics */
  244. int nOut; /* Number of outstanding pages */
  245. int nWrite; /* Total number of pages written */
  246. int nRead; /* Total number of pages read */
  247. };
  248. /*
  249. ** Database page handle.
  250. **
  251. ** pSeg:
  252. ** When lsmFsSortedAppend() is called on a compressed database, the new
  253. ** page is not assigned a page number or location in the database file
  254. ** immediately. Instead, these are assigned by the lsmFsPagePersist() call
  255. ** right before it writes the compressed page image to disk.
  256. **
  257. ** The lsmFsSortedAppend() function sets the pSeg pointer to point to the
  258. ** segment that the new page will be a part of. It is unset by
  259. ** lsmFsPagePersist() after the page is written to disk.
  260. */
  261. struct Page {
  262. u8 *aData; /* Buffer containing page data */
  263. int nData; /* Bytes of usable data at aData[] */
  264. LsmPgno iPg; /* Page number */
  265. int nRef; /* Number of outstanding references */
  266. int flags; /* Combination of PAGE_XXX flags */
  267. Page *pHashNext; /* Next page in hash table slot */
  268. Page *pLruNext; /* Next page in LRU list */
  269. Page *pLruPrev; /* Previous page in LRU list */
  270. FileSystem *pFS; /* File system that owns this page */
  271. /* Only used in compressed database mode: */
  272. int nCompress; /* Compressed size (or 0 for uncomp. db) */
  273. int nCompressPrev; /* Compressed size of prev page */
  274. Segment *pSeg; /* Segment this page will be written to */
  275. /* Pointers for singly linked lists */
  276. Page *pWaitingNext; /* Next page in FileSystem.pWaiting list */
  277. Page *pFreeNext; /* Next page in FileSystem.pFree list */
  278. Page *pMappedNext; /* Next page in FileSystem.pMapped list */
  279. };
  280. /*
  281. ** Meta-data page handle. There are two meta-data pages at the start of
  282. ** the database file, each FileSystem.nMetasize bytes in size.
  283. */
  284. struct MetaPage {
  285. int iPg; /* Either 1 or 2 */
  286. int bWrite; /* Write back to db file on release */
  287. u8 *aData; /* Pointer to buffer */
  288. FileSystem *pFS; /* FileSystem that owns this page */
  289. };
  290. /*
  291. ** Values for LsmPage.flags
  292. */
  293. #define PAGE_DIRTY 0x00000001 /* Set if page is dirty */
  294. #define PAGE_FREE 0x00000002 /* Set if Page.aData requires lsmFree() */
  295. #define PAGE_HASPREV 0x00000004 /* Set if page is first on uncomp. block */
  296. /*
  297. ** Number of pgsz byte pages omitted from the start of block 1. The start
  298. ** of block 1 contains two 4096 byte meta pages (8192 bytes in total).
  299. */
  300. #define BLOCK1_HDR_SIZE(pgsz) LSM_MAX(1, 8192/(pgsz))
  301. /*
  302. ** If NDEBUG is not defined, set a breakpoint in function lsmIoerrBkpt()
  303. ** to catch IO errors (any error returned by a VFS method).
  304. */
  305. #ifndef NDEBUG
  306. static void lsmIoerrBkpt(void){
  307. static int nErr = 0;
  308. nErr++;
  309. }
  310. static int IOERR_WRAPPER(int rc){
  311. if( rc!=LSM_OK ) lsmIoerrBkpt();
  312. return rc;
  313. }
  314. #else
  315. # define IOERR_WRAPPER(rc) (rc)
  316. #endif
  317. #ifdef NDEBUG
  318. # define assert_lists_are_ok(x)
  319. #else
  320. static Page *fsPageFindInHash(FileSystem *pFS, LsmPgno iPg, int *piHash);
  321. static void assert_lists_are_ok(FileSystem *pFS){
  322. #if 0
  323. Page *p;
  324. assert( pFS->nMapLimit>=0 );
  325. /* Check that all pages in the LRU list have nRef==0, pointers to buffers
  326. ** in heap memory, and corresponding entries in the hash table. */
  327. for(p=pFS->pLruFirst; p; p=p->pLruNext){
  328. assert( p==pFS->pLruFirst || p->pLruPrev!=0 );
  329. assert( p==pFS->pLruLast || p->pLruNext!=0 );
  330. assert( p->pLruPrev==0 || p->pLruPrev->pLruNext==p );
  331. assert( p->pLruNext==0 || p->pLruNext->pLruPrev==p );
  332. assert( p->nRef==0 );
  333. assert( p->flags & PAGE_FREE );
  334. assert( p==fsPageFindInHash(pFS, p->iPg, 0) );
  335. }
  336. #endif
  337. }
  338. #endif
  339. /*
  340. ** Wrappers around the VFS methods of the lsm_env object:
  341. **
  342. ** lsmEnvOpen()
  343. ** lsmEnvRead()
  344. ** lsmEnvWrite()
  345. ** lsmEnvSync()
  346. ** lsmEnvSectorSize()
  347. ** lsmEnvClose()
  348. ** lsmEnvTruncate()
  349. ** lsmEnvUnlink()
  350. ** lsmEnvRemap()
  351. */
  352. int lsmEnvOpen(lsm_env *pEnv, const char *zFile, int flags, lsm_file **ppNew){
  353. return pEnv->xOpen(pEnv, zFile, flags, ppNew);
  354. }
  355. static int lsmEnvRead(
  356. lsm_env *pEnv,
  357. lsm_file *pFile,
  358. lsm_i64 iOff,
  359. void *pRead,
  360. int nRead
  361. ){
  362. return IOERR_WRAPPER( pEnv->xRead(pFile, iOff, pRead, nRead) );
  363. }
  364. static int lsmEnvWrite(
  365. lsm_env *pEnv,
  366. lsm_file *pFile,
  367. lsm_i64 iOff,
  368. const void *pWrite,
  369. int nWrite
  370. ){
  371. return IOERR_WRAPPER( pEnv->xWrite(pFile, iOff, (void *)pWrite, nWrite) );
  372. }
  373. static int lsmEnvSync(lsm_env *pEnv, lsm_file *pFile){
  374. return IOERR_WRAPPER( pEnv->xSync(pFile) );
  375. }
  376. static int lsmEnvSectorSize(lsm_env *pEnv, lsm_file *pFile){
  377. return pEnv->xSectorSize(pFile);
  378. }
  379. int lsmEnvClose(lsm_env *pEnv, lsm_file *pFile){
  380. return IOERR_WRAPPER( pEnv->xClose(pFile) );
  381. }
  382. static int lsmEnvTruncate(lsm_env *pEnv, lsm_file *pFile, lsm_i64 nByte){
  383. return IOERR_WRAPPER( pEnv->xTruncate(pFile, nByte) );
  384. }
  385. static int lsmEnvUnlink(lsm_env *pEnv, const char *zDel){
  386. return IOERR_WRAPPER( pEnv->xUnlink(pEnv, zDel) );
  387. }
  388. static int lsmEnvRemap(
  389. lsm_env *pEnv,
  390. lsm_file *pFile,
  391. i64 szMin,
  392. void **ppMap,
  393. i64 *pszMap
  394. ){
  395. return pEnv->xRemap(pFile, szMin, ppMap, pszMap);
  396. }
  397. int lsmEnvLock(lsm_env *pEnv, lsm_file *pFile, int iLock, int eLock){
  398. if( pFile==0 ) return LSM_OK;
  399. return pEnv->xLock(pFile, iLock, eLock);
  400. }
  401. int lsmEnvTestLock(
  402. lsm_env *pEnv,
  403. lsm_file *pFile,
  404. int iLock,
  405. int nLock,
  406. int eLock
  407. ){
  408. return pEnv->xTestLock(pFile, iLock, nLock, eLock);
  409. }
  410. int lsmEnvShmMap(
  411. lsm_env *pEnv,
  412. lsm_file *pFile,
  413. int iChunk,
  414. int sz,
  415. void **ppOut
  416. ){
  417. return pEnv->xShmMap(pFile, iChunk, sz, ppOut);
  418. }
  419. void lsmEnvShmBarrier(lsm_env *pEnv){
  420. pEnv->xShmBarrier();
  421. }
  422. void lsmEnvShmUnmap(lsm_env *pEnv, lsm_file *pFile, int bDel){
  423. pEnv->xShmUnmap(pFile, bDel);
  424. }
  425. void lsmEnvSleep(lsm_env *pEnv, int nUs){
  426. pEnv->xSleep(pEnv, nUs);
  427. }
  428. /*
  429. ** Write the contents of string buffer pStr into the log file, starting at
  430. ** offset iOff.
  431. */
  432. int lsmFsWriteLog(FileSystem *pFS, i64 iOff, LsmString *pStr){
  433. assert( pFS->fdLog );
  434. return lsmEnvWrite(pFS->pEnv, pFS->fdLog, iOff, pStr->z, pStr->n);
  435. }
  436. /*
  437. ** fsync() the log file.
  438. */
  439. int lsmFsSyncLog(FileSystem *pFS){
  440. assert( pFS->fdLog );
  441. return lsmEnvSync(pFS->pEnv, pFS->fdLog);
  442. }
  443. /*
  444. ** Read nRead bytes of data starting at offset iOff of the log file. Append
  445. ** the results to string buffer pStr.
  446. */
  447. int lsmFsReadLog(FileSystem *pFS, i64 iOff, int nRead, LsmString *pStr){
  448. int rc; /* Return code */
  449. assert( pFS->fdLog );
  450. rc = lsmStringExtend(pStr, nRead);
  451. if( rc==LSM_OK ){
  452. rc = lsmEnvRead(pFS->pEnv, pFS->fdLog, iOff, &pStr->z[pStr->n], nRead);
  453. pStr->n += nRead;
  454. }
  455. return rc;
  456. }
  457. /*
  458. ** Truncate the log file to nByte bytes in size.
  459. */
  460. int lsmFsTruncateLog(FileSystem *pFS, i64 nByte){
  461. if( pFS->fdLog==0 ) return LSM_OK;
  462. return lsmEnvTruncate(pFS->pEnv, pFS->fdLog, nByte);
  463. }
  464. /*
  465. ** Truncate the db file to nByte bytes in size.
  466. */
  467. int lsmFsTruncateDb(FileSystem *pFS, i64 nByte){
  468. if( pFS->fdDb==0 ) return LSM_OK;
  469. return lsmEnvTruncate(pFS->pEnv, pFS->fdDb, nByte);
  470. }
  471. /*
  472. ** Close the log file. Then delete it from the file-system. This function
  473. ** is called during database shutdown only.
  474. */
  475. int lsmFsCloseAndDeleteLog(FileSystem *pFS){
  476. char *zDel;
  477. if( pFS->fdLog ){
  478. lsmEnvClose(pFS->pEnv, pFS->fdLog );
  479. pFS->fdLog = 0;
  480. }
  481. zDel = lsmMallocPrintf(pFS->pEnv, "%s-log", pFS->zDb);
  482. if( zDel ){
  483. lsmEnvUnlink(pFS->pEnv, zDel);
  484. lsmFree(pFS->pEnv, zDel);
  485. }
  486. return LSM_OK;
  487. }
  488. /*
  489. ** Return true if page iReal of the database should be accessed using mmap.
  490. ** False otherwise.
  491. */
  492. static int fsMmapPage(FileSystem *pFS, LsmPgno iReal){
  493. return ((i64)iReal*pFS->nPagesize <= pFS->nMapLimit);
  494. }
  495. /*
  496. ** Given that there are currently nHash slots in the hash table, return
  497. ** the hash key for file iFile, page iPg.
  498. */
  499. static int fsHashKey(int nHash, LsmPgno iPg){
  500. return (iPg % nHash);
  501. }
  502. /*
  503. ** This is a helper function for lsmFsOpen(). It opens a single file on
  504. ** disk (either the database or log file).
  505. */
  506. static lsm_file *fsOpenFile(
  507. FileSystem *pFS, /* File system object */
  508. int bReadonly, /* True to open this file read-only */
  509. int bLog, /* True for log, false for db */
  510. int *pRc /* IN/OUT: Error code */
  511. ){
  512. lsm_file *pFile = 0;
  513. if( *pRc==LSM_OK ){
  514. int flags = (bReadonly ? LSM_OPEN_READONLY : 0);
  515. const char *zPath = (bLog ? pFS->zLog : pFS->zDb);
  516. *pRc = lsmEnvOpen(pFS->pEnv, zPath, flags, &pFile);
  517. }
  518. return pFile;
  519. }
  520. /*
  521. ** If it is not already open, this function opens the log file. It returns
  522. ** LSM_OK if successful (or if the log file was already open) or an LSM
  523. ** error code otherwise.
  524. **
  525. ** The log file must be opened before any of the following may be called:
  526. **
  527. ** lsmFsWriteLog
  528. ** lsmFsSyncLog
  529. ** lsmFsReadLog
  530. */
  531. int lsmFsOpenLog(lsm_db *db, int *pbOpen){
  532. int rc = LSM_OK;
  533. FileSystem *pFS = db->pFS;
  534. if( 0==pFS->fdLog ){
  535. pFS->fdLog = fsOpenFile(pFS, db->bReadonly, 1, &rc);
  536. if( rc==LSM_IOERR_NOENT && db->bReadonly ){
  537. rc = LSM_OK;
  538. }
  539. }
  540. if( pbOpen ) *pbOpen = (pFS->fdLog!=0);
  541. return rc;
  542. }
  543. /*
  544. ** Close the log file, if it is open.
  545. */
  546. void lsmFsCloseLog(lsm_db *db){
  547. FileSystem *pFS = db->pFS;
  548. if( pFS->fdLog ){
  549. lsmEnvClose(pFS->pEnv, pFS->fdLog);
  550. pFS->fdLog = 0;
  551. }
  552. }
  553. /*
  554. ** Open a connection to a database stored within the file-system.
  555. **
  556. ** If parameter bReadonly is true, then open a read-only file-descriptor
  557. ** on the database file. It is possible that bReadonly will be false even
  558. ** if the user requested that pDb be opened read-only. This is because the
  559. ** file-descriptor may later on be recycled by a read-write connection.
  560. ** If the db file can be opened for read-write access, it always is. Parameter
  561. ** bReadonly is only ever true if it has already been determined that the
  562. ** db can only be opened for read-only access.
  563. **
  564. ** Return LSM_OK if successful or an lsm error code otherwise.
  565. */
  566. int lsmFsOpen(
  567. lsm_db *pDb, /* Database connection to open fd for */
  568. const char *zDb, /* Full path to database file */
  569. int bReadonly /* True to open db file read-only */
  570. ){
  571. FileSystem *pFS;
  572. int rc = LSM_OK;
  573. int nDb = strlen(zDb);
  574. int nByte;
  575. assert( pDb->pFS==0 );
  576. assert( pDb->pWorker==0 && pDb->pClient==0 );
  577. nByte = sizeof(FileSystem) + nDb+1 + nDb+4+1;
  578. pFS = (FileSystem *)lsmMallocZeroRc(pDb->pEnv, nByte, &rc);
  579. if( pFS ){
  580. LsmFile *pLsmFile;
  581. pFS->zDb = (char *)&pFS[1];
  582. pFS->zLog = &pFS->zDb[nDb+1];
  583. pFS->nPagesize = LSM_DFLT_PAGE_SIZE;
  584. pFS->nBlocksize = LSM_DFLT_BLOCK_SIZE;
  585. pFS->nMetasize = LSM_META_PAGE_SIZE;
  586. pFS->nMetaRwSize = LSM_META_RW_PAGE_SIZE;
  587. pFS->pDb = pDb;
  588. pFS->pEnv = pDb->pEnv;
  589. /* Make a copy of the database and log file names. */
  590. memcpy(pFS->zDb, zDb, nDb+1);
  591. memcpy(pFS->zLog, zDb, nDb);
  592. memcpy(&pFS->zLog[nDb], "-log", 5);
  593. /* Allocate the hash-table here. At some point, it should be changed
  594. ** so that it can grow dynamicly. */
  595. pFS->nCacheMax = 2048*1024 / pFS->nPagesize;
  596. pFS->nHash = 4096;
  597. pFS->apHash = lsmMallocZeroRc(pDb->pEnv, sizeof(Page *) * pFS->nHash, &rc);
  598. /* Open the database file */
  599. pLsmFile = lsmDbRecycleFd(pDb);
  600. if( pLsmFile ){
  601. pFS->pLsmFile = pLsmFile;
  602. pFS->fdDb = pLsmFile->pFile;
  603. memset(pLsmFile, 0, sizeof(LsmFile));
  604. }else{
  605. pFS->pLsmFile = lsmMallocZeroRc(pDb->pEnv, sizeof(LsmFile), &rc);
  606. if( rc==LSM_OK ){
  607. pFS->fdDb = fsOpenFile(pFS, bReadonly, 0, &rc);
  608. }
  609. }
  610. if( rc!=LSM_OK ){
  611. lsmFsClose(pFS);
  612. pFS = 0;
  613. }else{
  614. pFS->szSector = lsmEnvSectorSize(pFS->pEnv, pFS->fdDb);
  615. }
  616. }
  617. pDb->pFS = pFS;
  618. return rc;
  619. }
  620. /*
  621. ** Configure the file-system object according to the current values of
  622. ** the LSM_CONFIG_MMAP and LSM_CONFIG_SET_COMPRESSION options.
  623. */
  624. int lsmFsConfigure(lsm_db *db){
  625. FileSystem *pFS = db->pFS;
  626. if( pFS ){
  627. lsm_env *pEnv = pFS->pEnv;
  628. Page *pPg;
  629. assert( pFS->nOut==0 );
  630. assert( pFS->pWaiting==0 );
  631. assert( pFS->pMapped==0 );
  632. /* Reset any compression/decompression buffers already allocated */
  633. lsmFree(pEnv, pFS->aIBuffer);
  634. lsmFree(pEnv, pFS->aOBuffer);
  635. pFS->nBuffer = 0;
  636. /* Unmap the file, if it is currently mapped */
  637. if( pFS->pMap ){
  638. lsmEnvRemap(pEnv, pFS->fdDb, -1, &pFS->pMap, &pFS->nMap);
  639. pFS->nMapLimit = 0;
  640. }
  641. /* Free all allocated page structures */
  642. pPg = pFS->pLruFirst;
  643. while( pPg ){
  644. Page *pNext = pPg->pLruNext;
  645. assert( pPg->flags & PAGE_FREE );
  646. lsmFree(pEnv, pPg->aData);
  647. lsmFree(pEnv, pPg);
  648. pPg = pNext;
  649. }
  650. pPg = pFS->pFree;
  651. while( pPg ){
  652. Page *pNext = pPg->pFreeNext;
  653. lsmFree(pEnv, pPg);
  654. pPg = pNext;
  655. }
  656. /* Zero pointers that point to deleted page objects */
  657. pFS->nCacheAlloc = 0;
  658. pFS->pLruFirst = 0;
  659. pFS->pLruLast = 0;
  660. pFS->pFree = 0;
  661. if( pFS->apHash ){
  662. memset(pFS->apHash, 0, pFS->nHash*sizeof(pFS->apHash[0]));
  663. }
  664. /* Configure the FileSystem object */
  665. if( db->compress.xCompress ){
  666. pFS->pCompress = &db->compress;
  667. pFS->nMapLimit = 0;
  668. }else{
  669. pFS->pCompress = 0;
  670. if( db->iMmap==1 ){
  671. /* Unlimited */
  672. pFS->nMapLimit = (i64)1 << 60;
  673. }else{
  674. /* iMmap is a limit in KB. Set nMapLimit to the same value in bytes. */
  675. pFS->nMapLimit = (i64)db->iMmap * 1024;
  676. }
  677. }
  678. }
  679. return LSM_OK;
  680. }
  681. /*
  682. ** Close and destroy a FileSystem object.
  683. */
  684. void lsmFsClose(FileSystem *pFS){
  685. if( pFS ){
  686. Page *pPg;
  687. lsm_env *pEnv = pFS->pEnv;
  688. assert( pFS->nOut==0 );
  689. pPg = pFS->pLruFirst;
  690. while( pPg ){
  691. Page *pNext = pPg->pLruNext;
  692. if( pPg->flags & PAGE_FREE ) lsmFree(pEnv, pPg->aData);
  693. lsmFree(pEnv, pPg);
  694. pPg = pNext;
  695. }
  696. pPg = pFS->pFree;
  697. while( pPg ){
  698. Page *pNext = pPg->pFreeNext;
  699. if( pPg->flags & PAGE_FREE ) lsmFree(pEnv, pPg->aData);
  700. lsmFree(pEnv, pPg);
  701. pPg = pNext;
  702. }
  703. if( pFS->fdDb ) lsmEnvClose(pFS->pEnv, pFS->fdDb );
  704. if( pFS->fdLog ) lsmEnvClose(pFS->pEnv, pFS->fdLog );
  705. lsmFree(pEnv, pFS->pLsmFile);
  706. lsmFree(pEnv, pFS->apHash);
  707. lsmFree(pEnv, pFS->aIBuffer);
  708. lsmFree(pEnv, pFS->aOBuffer);
  709. lsmFree(pEnv, pFS);
  710. }
  711. }
  712. /*
  713. ** This function is called when closing a database handle (i.e. lsm_close())
  714. ** if there exist other connections to the same database within this process.
  715. ** In that case the file-descriptor open on the database file is not closed
  716. ** when the FileSystem object is destroyed, as this would cause any POSIX
  717. ** locks held by the other connections to be silently dropped (see "man close"
  718. ** for details). Instead, the file-descriptor is stored in a list by the
  719. ** lsm_shared.c module until it is either closed or reused.
  720. **
  721. ** This function returns a pointer to an object that can be linked into
  722. ** the list described above. The returned object now 'owns' the database
  723. ** file descriptor, so that when the FileSystem object is destroyed, it
  724. ** will not be closed.
  725. **
  726. ** This function may be called at most once in the life-time of a
  727. ** FileSystem object. The results of any operations involving the database
  728. ** file descriptor are undefined once this function has been called.
  729. **
  730. ** None of this is necessary on non-POSIX systems. But we do it anyway in
  731. ** the name of using as similar code as possible on all platforms.
  732. */
  733. LsmFile *lsmFsDeferClose(FileSystem *pFS){
  734. LsmFile *p = pFS->pLsmFile;
  735. assert( p->pNext==0 );
  736. p->pFile = pFS->fdDb;
  737. pFS->fdDb = 0;
  738. pFS->pLsmFile = 0;
  739. return p;
  740. }
  741. /*
  742. ** Allocate a buffer and populate it with the output of the xFileid()
  743. ** method of the database file handle. If successful, set *ppId to point
  744. ** to the buffer and *pnId to the number of bytes in the buffer and return
  745. ** LSM_OK. Otherwise, set *ppId and *pnId to zero and return an LSM
  746. ** error code.
  747. */
  748. int lsmFsFileid(lsm_db *pDb, void **ppId, int *pnId){
  749. lsm_env *pEnv = pDb->pEnv;
  750. FileSystem *pFS = pDb->pFS;
  751. int rc;
  752. int nId = 0;
  753. void *pId;
  754. rc = pEnv->xFileid(pFS->fdDb, 0, &nId);
  755. pId = lsmMallocZeroRc(pEnv, nId, &rc);
  756. if( rc==LSM_OK ) rc = pEnv->xFileid(pFS->fdDb, pId, &nId);
  757. if( rc!=LSM_OK ){
  758. lsmFree(pEnv, pId);
  759. pId = 0;
  760. nId = 0;
  761. }
  762. *ppId = pId;
  763. *pnId = nId;
  764. return rc;
  765. }
  766. /*
  767. ** Return the nominal page-size used by this file-system. Actual pages
  768. ** may be smaller or larger than this value.
  769. */
  770. int lsmFsPageSize(FileSystem *pFS){
  771. return pFS->nPagesize;
  772. }
  773. /*
  774. ** Return the block-size used by this file-system.
  775. */
  776. int lsmFsBlockSize(FileSystem *pFS){
  777. return pFS->nBlocksize;
  778. }
  779. /*
  780. ** Configure the nominal page-size used by this file-system. Actual
  781. ** pages may be smaller or larger than this value.
  782. */
  783. void lsmFsSetPageSize(FileSystem *pFS, int nPgsz){
  784. pFS->nPagesize = nPgsz;
  785. pFS->nCacheMax = 2048*1024 / pFS->nPagesize;
  786. }
  787. /*
  788. ** Configure the block-size used by this file-system.
  789. */
  790. void lsmFsSetBlockSize(FileSystem *pFS, int nBlocksize){
  791. pFS->nBlocksize = nBlocksize;
  792. }
  793. /*
  794. ** Return the page number of the first page on block iBlock. Blocks are
  795. ** numbered starting from 1.
  796. **
  797. ** For a compressed database, page numbers are byte offsets. The first
  798. ** page on each block is the byte offset immediately following the 4-byte
  799. ** "previous block" pointer at the start of each block.
  800. */
  801. static LsmPgno fsFirstPageOnBlock(FileSystem *pFS, int iBlock){
  802. LsmPgno iPg;
  803. if( pFS->pCompress ){
  804. if( iBlock==1 ){
  805. iPg = pFS->nMetasize * 2 + 4;
  806. }else{
  807. iPg = pFS->nBlocksize * (LsmPgno)(iBlock-1) + 4;
  808. }
  809. }else{
  810. const i64 nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
  811. if( iBlock==1 ){
  812. iPg = 1 + ((pFS->nMetasize*2 + pFS->nPagesize - 1) / pFS->nPagesize);
  813. }else{
  814. iPg = 1 + (iBlock-1) * nPagePerBlock;
  815. }
  816. }
  817. return iPg;
  818. }
  819. /*
  820. ** Return the page number of the last page on block iBlock. Blocks are
  821. ** numbered starting from 1.
  822. **
  823. ** For a compressed database, page numbers are byte offsets. The first
  824. ** page on each block is the byte offset of the byte immediately before
  825. ** the 4-byte "next block" pointer at the end of each block.
  826. */
  827. static LsmPgno fsLastPageOnBlock(FileSystem *pFS, int iBlock){
  828. if( pFS->pCompress ){
  829. return pFS->nBlocksize * (LsmPgno)iBlock - 1 - 4;
  830. }else{
  831. const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
  832. return iBlock * nPagePerBlock;
  833. }
  834. }
  835. /*
  836. ** Return the block number of the block that page iPg is located on.
  837. ** Blocks are numbered starting from 1.
  838. */
  839. static int fsPageToBlock(FileSystem *pFS, LsmPgno iPg){
  840. if( pFS->pCompress ){
  841. return (int)((iPg / pFS->nBlocksize) + 1);
  842. }else{
  843. return (int)(1 + ((iPg-1) / (pFS->nBlocksize / pFS->nPagesize)));
  844. }
  845. }
  846. /*
  847. ** Return true if page iPg is the last page on its block.
  848. **
  849. ** This function is only called in non-compressed database mode.
  850. */
  851. static int fsIsLast(FileSystem *pFS, LsmPgno iPg){
  852. const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
  853. assert( !pFS->pCompress );
  854. return ( iPg && (iPg % nPagePerBlock)==0 );
  855. }
  856. /*
  857. ** Return true if page iPg is the first page on its block.
  858. **
  859. ** This function is only called in non-compressed database mode.
  860. */
  861. static int fsIsFirst(FileSystem *pFS, LsmPgno iPg){
  862. const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
  863. assert( !pFS->pCompress );
  864. return ( (iPg % nPagePerBlock)==1
  865. || (iPg<nPagePerBlock && iPg==fsFirstPageOnBlock(pFS, 1))
  866. );
  867. }
  868. /*
  869. ** Given a page reference, return a pointer to the buffer containing the
  870. ** pages contents. If parameter pnData is not NULL, set *pnData to the size
  871. ** of the buffer in bytes before returning.
  872. */
  873. u8 *lsmFsPageData(Page *pPage, int *pnData){
  874. if( pnData ){
  875. *pnData = pPage->nData;
  876. }
  877. return pPage->aData;
  878. }
  879. /*
  880. ** Return the page number of a page.
  881. */
  882. LsmPgno lsmFsPageNumber(Page *pPage){
  883. /* assert( (pPage->flags & PAGE_DIRTY)==0 ); */
  884. return pPage ? pPage->iPg : 0;
  885. }
  886. /*
  887. ** Page pPg is currently part of the LRU list belonging to pFS. Remove
  888. ** it from the list. pPg->pLruNext and pPg->pLruPrev are cleared by this
  889. ** operation.
  890. */
  891. static void fsPageRemoveFromLru(FileSystem *pFS, Page *pPg){
  892. assert( pPg->pLruNext || pPg==pFS->pLruLast );
  893. assert( pPg->pLruPrev || pPg==pFS->pLruFirst );
  894. if( pPg->pLruNext ){
  895. pPg->pLruNext->pLruPrev = pPg->pLruPrev;
  896. }else{
  897. pFS->pLruLast = pPg->pLruPrev;
  898. }
  899. if( pPg->pLruPrev ){
  900. pPg->pLruPrev->pLruNext = pPg->pLruNext;
  901. }else{
  902. pFS->pLruFirst = pPg->pLruNext;
  903. }
  904. pPg->pLruPrev = 0;
  905. pPg->pLruNext = 0;
  906. }
  907. /*
  908. ** Page pPg is not currently part of the LRU list belonging to pFS. Add it.
  909. */
  910. static void fsPageAddToLru(FileSystem *pFS, Page *pPg){
  911. assert( pPg->pLruNext==0 && pPg->pLruPrev==0 );
  912. pPg->pLruPrev = pFS->pLruLast;
  913. if( pPg->pLruPrev ){
  914. pPg->pLruPrev->pLruNext = pPg;
  915. }else{
  916. pFS->pLruFirst = pPg;
  917. }
  918. pFS->pLruLast = pPg;
  919. }
  920. /*
  921. ** Page pPg is currently stored in the apHash/nHash hash table. Remove it.
  922. */
  923. static void fsPageRemoveFromHash(FileSystem *pFS, Page *pPg){
  924. int iHash;
  925. Page **pp;
  926. iHash = fsHashKey(pFS->nHash, pPg->iPg);
  927. for(pp=&pFS->apHash[iHash]; *pp!=pPg; pp=&(*pp)->pHashNext);
  928. *pp = pPg->pHashNext;
  929. pPg->pHashNext = 0;
  930. }
  931. /*
  932. ** Free a Page object allocated by fsPageBuffer().
  933. */
  934. static void fsPageBufferFree(Page *pPg){
  935. pPg->pFS->nCacheAlloc--;
  936. lsmFree(pPg->pFS->pEnv, pPg->aData);
  937. lsmFree(pPg->pFS->pEnv, pPg);
  938. }
  939. /*
  940. ** Purge the cache of all non-mmap pages with nRef==0.
  941. */
  942. void lsmFsPurgeCache(FileSystem *pFS){
  943. Page *pPg;
  944. pPg = pFS->pLruFirst;
  945. while( pPg ){
  946. Page *pNext = pPg->pLruNext;
  947. assert( pPg->flags & PAGE_FREE );
  948. fsPageRemoveFromHash(pFS, pPg);
  949. fsPageBufferFree(pPg);
  950. pPg = pNext;
  951. }
  952. pFS->pLruFirst = 0;
  953. pFS->pLruLast = 0;
  954. assert( pFS->nCacheAlloc<=pFS->nOut && pFS->nCacheAlloc>=0 );
  955. }
  956. /*
  957. ** Search the hash-table for page iPg. If an entry is round, return a pointer
  958. ** to it. Otherwise, return NULL.
  959. **
  960. ** Either way, if argument piHash is not NULL set *piHash to the hash slot
  961. ** number that page iPg would be stored in before returning.
  962. */
  963. static Page *fsPageFindInHash(FileSystem *pFS, LsmPgno iPg, int *piHash){
  964. Page *p; /* Return value */
  965. int iHash = fsHashKey(pFS->nHash, iPg);
  966. if( piHash ) *piHash = iHash;
  967. for(p=pFS->apHash[iHash]; p; p=p->pHashNext){
  968. if( p->iPg==iPg) break;
  969. }
  970. return p;
  971. }
  972. /*
  973. ** Allocate and return a non-mmap Page object. If there are already
  974. ** nCacheMax such Page objects outstanding, try to recycle an existing
  975. ** Page instead.
  976. */
  977. static int fsPageBuffer(
  978. FileSystem *pFS,
  979. Page **ppOut
  980. ){
  981. int rc = LSM_OK;
  982. Page *pPage = 0;
  983. if( pFS->pLruFirst==0 || pFS->nCacheAlloc<pFS->nCacheMax ){
  984. /* Allocate a new Page object */
  985. pPage = lsmMallocZero(pFS->pEnv, sizeof(Page));
  986. if( !pPage ){
  987. rc = LSM_NOMEM_BKPT;
  988. }else{
  989. pPage->aData = (u8 *)lsmMalloc(pFS->pEnv, pFS->nPagesize);
  990. if( !pPage->aData ){
  991. lsmFree(pFS->pEnv, pPage);
  992. rc = LSM_NOMEM_BKPT;
  993. pPage = 0;
  994. }else{
  995. pFS->nCacheAlloc++;
  996. }
  997. }
  998. }else{
  999. /* Reuse an existing Page object */
  1000. u8 *aData;
  1001. pPage = pFS->pLruFirst;
  1002. aData = pPage->aData;
  1003. fsPageRemoveFromLru(pFS, pPage);
  1004. fsPageRemoveFromHash(pFS, pPage);
  1005. memset(pPage, 0, sizeof(Page));
  1006. pPage->aData = aData;
  1007. }
  1008. if( pPage ){
  1009. pPage->flags = PAGE_FREE;
  1010. }
  1011. *ppOut = pPage;
  1012. return rc;
  1013. }
  1014. /*
  1015. ** Assuming *pRc is initially LSM_OK, attempt to ensure that the
  1016. ** memory-mapped region is at least iSz bytes in size. If it is not already,
  1017. ** iSz bytes in size, extend it and update the pointers associated with any
  1018. ** outstanding Page objects.
  1019. **
  1020. ** If *pRc is not LSM_OK when this function is called, it is a no-op.
  1021. ** Otherwise, *pRc is set to an lsm error code if an error occurs, or
  1022. ** left unmodified otherwise.
  1023. **
  1024. ** This function is never called in compressed database mode.
  1025. */
  1026. static void fsGrowMapping(
  1027. FileSystem *pFS, /* File system object */
  1028. i64 iSz, /* Minimum size to extend mapping to */
  1029. int *pRc /* IN/OUT: Error code */
  1030. ){
  1031. assert( PAGE_HASPREV==4 );
  1032. if( *pRc==LSM_OK && iSz>pFS->nMap ){
  1033. int rc;
  1034. u8 *aOld = pFS->pMap;
  1035. rc = lsmEnvRemap(pFS->pEnv, pFS->fdDb, iSz, &pFS->pMap, &pFS->nMap);
  1036. if( rc==LSM_OK && pFS->pMap!=aOld ){
  1037. Page *pFix;
  1038. i64 iOff = (u8 *)pFS->pMap - aOld;
  1039. for(pFix=pFS->pMapped; pFix; pFix=pFix->pMappedNext){
  1040. pFix->aData += iOff;
  1041. }
  1042. lsmSortedRemap(pFS->pDb);
  1043. }
  1044. *pRc = rc;
  1045. }
  1046. }
  1047. /*
  1048. ** If it is mapped, unmap the database file.
  1049. */
  1050. int lsmFsUnmap(FileSystem *pFS){
  1051. int rc = LSM_OK;
  1052. if( pFS ){
  1053. rc = lsmEnvRemap(pFS->pEnv, pFS->fdDb, -1, &pFS->pMap, &pFS->nMap);
  1054. }
  1055. return rc;
  1056. }
  1057. /*
  1058. ** fsync() the database file.
  1059. */
  1060. int lsmFsSyncDb(FileSystem *pFS, int nBlock){
  1061. return lsmEnvSync(pFS->pEnv, pFS->fdDb);
  1062. }
  1063. /*
  1064. ** If block iBlk has been redirected according to the redirections in the
  1065. ** object passed as the first argument, return the destination block to
  1066. ** which it is redirected. Otherwise, return a copy of iBlk.
  1067. */
  1068. static int fsRedirectBlock(Redirect *p, int iBlk){
  1069. if( p ){
  1070. int i;
  1071. for(i=0; i<p->n; i++){
  1072. if( iBlk==p->a[i].iFrom ) return p->a[i].iTo;
  1073. }
  1074. }
  1075. assert( iBlk!=0 );
  1076. return iBlk;
  1077. }
  1078. /*
  1079. ** If page iPg has been redirected according to the redirections in the
  1080. ** object passed as the second argument, return the destination page to
  1081. ** which it is redirected. Otherwise, return a copy of iPg.
  1082. */
  1083. LsmPgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, LsmPgno iPg){
  1084. LsmPgno iReal = iPg;
  1085. if( pRedir ){
  1086. const int nPagePerBlock = (
  1087. pFS->pCompress ? pFS->nBlocksize : (pFS->nBlocksize / pFS->nPagesize)
  1088. );
  1089. int iBlk = fsPageToBlock(pFS, iPg);
  1090. int i;
  1091. for(i=0; i<pRedir->n; i++){
  1092. int iFrom = pRedir->a[i].iFrom;
  1093. if( iFrom>iBlk ) break;
  1094. if( iFrom==iBlk ){
  1095. int iTo = pRedir->a[i].iTo;
  1096. iReal = iPg - (LsmPgno)(iFrom - iTo) * nPagePerBlock;
  1097. if( iTo==1 ){
  1098. iReal += (fsFirstPageOnBlock(pFS, 1)-1);
  1099. }
  1100. break;
  1101. }
  1102. }
  1103. }
  1104. assert( iReal!=0 );
  1105. return iReal;
  1106. }
  1107. /* Required by the circular fsBlockNext<->fsPageGet dependency. */
  1108. static int fsPageGet(FileSystem *, Segment *, LsmPgno, int, Page **, int *);
  1109. /*
  1110. ** Parameter iBlock is a database file block. This function reads the value
  1111. ** stored in the blocks "next block" pointer and stores it in *piNext.
  1112. ** LSM_OK is returned if everything is successful, or an LSM error code
  1113. ** otherwise.
  1114. */
  1115. static int fsBlockNext(
  1116. FileSystem *pFS, /* File-system object handle */
  1117. Segment *pSeg, /* Use this segment for block redirects */
  1118. int iBlock, /* Read field from this block */
  1119. int *piNext /* OUT: Next block in linked list */
  1120. ){
  1121. int rc;
  1122. int iRead; /* Read block from here */
  1123. if( pSeg ){
  1124. iRead = fsRedirectBlock(pSeg->pRedirect, iBlock);
  1125. }else{
  1126. iRead = iBlock;
  1127. }
  1128. assert( pFS->nMapLimit==0 || pFS->pCompress==0 );
  1129. if( pFS->pCompress ){
  1130. i64 iOff; /* File offset to read data from */
  1131. u8 aNext[4]; /* 4-byte pointer read from db file */
  1132. iOff = (i64)iRead * pFS->nBlocksize - sizeof(aNext);
  1133. rc = lsmEnvRead(pFS->pEnv, pFS->fdDb, iOff, aNext, sizeof(aNext));
  1134. if( rc==LSM_OK ){
  1135. *piNext = (int)lsmGetU32(aNext);
  1136. }
  1137. }else{
  1138. const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
  1139. Page *pLast;
  1140. rc = fsPageGet(pFS, 0, iRead*nPagePerBlock, 0, &pLast, 0);
  1141. if( rc==LSM_OK ){
  1142. *piNext = lsmGetU32(&pLast->aData[pFS->nPagesize-4]);
  1143. lsmFsPageRelease(pLast);
  1144. }
  1145. }
  1146. if( pSeg ){
  1147. *piNext = fsRedirectBlock(pSeg->pRedirect, *piNext);
  1148. }
  1149. return rc;
  1150. }
  1151. /*
  1152. ** Return the page number of the last page on the same block as page iPg.
  1153. */
  1154. LsmPgno fsLastPageOnPagesBlock(FileSystem *pFS, LsmPgno iPg){
  1155. return fsLastPageOnBlock(pFS, fsPageToBlock(pFS, iPg));
  1156. }
  1157. /*
  1158. ** Read nData bytes of data from offset iOff of the database file into
  1159. ** buffer aData. If this means reading past the end of a block, follow
  1160. ** the block pointer to the next block and continue reading.
  1161. **
  1162. ** Offset iOff is an absolute offset - not subject to any block redirection.
  1163. ** However any block pointer followed is. Use pSeg->pRedirect in this case.
  1164. **
  1165. ** This function is only called in compressed database mode.
  1166. */
  1167. static int fsReadData(
  1168. FileSystem *pFS, /* File-system handle */
  1169. Segment *pSeg, /* Block redirection */
  1170. i64 iOff, /* Read data from this offset */
  1171. u8 *aData, /* Buffer to read data into */
  1172. int nData /* Number of bytes to read */
  1173. ){
  1174. i64 iEob; /* End of block */
  1175. int nRead;
  1176. int rc;
  1177. assert( pFS->pCompress );
  1178. iEob = fsLastPageOnPagesBlock(pFS, iOff) + 1;
  1179. nRead = (int)LSM_MIN(iEob - iOff, nData);
  1180. rc = lsmEnvRead(pFS->pEnv, pFS->fdDb, iOff, aData, nRead);
  1181. if( rc==LSM_OK && nRead!=nData ){
  1182. int iBlk;
  1183. rc = fsBlockNext(pFS, pSeg, fsPageToBlock(pFS, iOff), &iBlk);
  1184. if( rc==LSM_OK ){
  1185. i64 iOff2 = fsFirstPageOnBlock(pFS, iBlk);
  1186. rc = lsmEnvRead(pFS->pEnv, pFS->fdDb, iOff2, &aData[nRead], nData-nRead);
  1187. }
  1188. }
  1189. return rc;
  1190. }
  1191. /*
  1192. ** Parameter iBlock is a database file block. This function reads the value
  1193. ** stored in the blocks "previous block" pointer and stores it in *piPrev.
  1194. ** LSM_OK is returned if everything is successful, or an LSM error code
  1195. ** otherwise.
  1196. */
  1197. static int fsBlockPrev(
  1198. FileSystem *pFS, /* File-system object handle */
  1199. Segment *pSeg, /* Use this segment for block redirects */
  1200. int iBlock, /* Read field from this block */
  1201. int *piPrev /* OUT: Previous block in linked list */
  1202. ){
  1203. int rc = LSM_OK; /* Return code */
  1204. assert( pFS->nMapLimit==0 || pFS->pCompress==0 );
  1205. assert( iBlock>0 );
  1206. if( pFS->pCompress ){
  1207. i64 iOff = fsFirstPageOnBlock(pFS, iBlock) - 4;
  1208. u8 aPrev[4]; /* 4-byte pointer read from db file */
  1209. rc = lsmEnvRead(pFS->pEnv, pFS->fdDb, iOff, aPrev, sizeof(aPrev));
  1210. if( rc==LSM_OK ){
  1211. Redirect *pRedir = (pSeg ? pSeg->pRedirect : 0);
  1212. *piPrev = fsRedirectBlock(pRedir, (int)lsmGetU32(aPrev));
  1213. }
  1214. }else{
  1215. assert( 0 );
  1216. }
  1217. return rc;
  1218. }
  1219. /*
  1220. ** Encode and decode routines for record size fields.
  1221. */
  1222. static void putRecordSize(u8 *aBuf, int nByte, int bFree){
  1223. aBuf[0] = (u8)(nByte >> 14) | 0x80;
  1224. aBuf[1] = ((u8)(nByte >> 7) & 0x7F) | (bFree ? 0x00 : 0x80);
  1225. aBuf[2] = (u8)nByte | 0x80;
  1226. }
  1227. static int getRecordSize(u8 *aBuf, int *pbFree){
  1228. int nByte;
  1229. nByte = (aBuf[0] & 0x7F) << 14;
  1230. nByte += (aBuf[1] & 0x7F) << 7;
  1231. nByte += (aBuf[2] & 0x7F);
  1232. *pbFree = !(aBuf[1] & 0x80);
  1233. return nByte;
  1234. }
  1235. /*
  1236. ** Subtract iSub from database file offset iOff and set *piRes to the
  1237. ** result. If doing so means passing the start of a block, follow the
  1238. ** block pointer stored in the first 4 bytes of the block.
  1239. **
  1240. ** Offset iOff is an absolute offset - not subject to any block redirection.
  1241. ** However any block pointer followed is. Use pSeg->pRedirect in this case.
  1242. **
  1243. ** Return LSM_OK if successful or an lsm error code if an error occurs.
  1244. */
  1245. static int fsSubtractOffset(
  1246. FileSystem *pFS,
  1247. Segment *pSeg,
  1248. i64 iOff,
  1249. int iSub,
  1250. i64 *piRes
  1251. ){
  1252. i64 iStart;
  1253. int iBlk = 0;
  1254. int rc;
  1255. assert( pFS->pCompress );
  1256. iStart = fsFirstPageOnBlock(pFS, fsPageToBlock(pFS, iOff));
  1257. if( (iOff-iSub)>=iStart ){
  1258. *piRes = (iOff-iSub);
  1259. return LSM_OK;
  1260. }
  1261. rc = fsBlockPrev(pFS, pSeg, fsPageToBlock(pFS, iOff), &iBlk);
  1262. *piRes = fsLastPageOnBlock(pFS, iBlk) - iSub + (iOff - iStart + 1);
  1263. return rc;
  1264. }
  1265. /*
  1266. ** Add iAdd to database file offset iOff and set *piRes to the
  1267. ** result. If doing so means passing the end of a block, follow the
  1268. ** block pointer stored in the last 4 bytes of the block.
  1269. **
  1270. ** Offset iOff is an absolute offset - not subject to any block redirection.
  1271. ** However any block pointer followed is. Use pSeg->pRedirect in this case.
  1272. **
  1273. ** Return LSM_OK if successful or an lsm error code if an error occurs.
  1274. */
  1275. static int fsAddOffset(
  1276. FileSystem *pFS,
  1277. Segment *pSeg,
  1278. i64 iOff,
  1279. int iAdd,
  1280. i64 *piRes
  1281. ){
  1282. i64 iEob;
  1283. int iBlk;
  1284. int rc;
  1285. assert( pFS->pCompress );
  1286. iEob = fsLastPageOnPagesBlock(pFS, iOff);
  1287. if( (iOff+iAdd)<=iEob ){
  1288. *piRes = (iOff+iAdd);
  1289. return LSM_OK;
  1290. }
  1291. rc = fsBlockNext(pFS, pSeg, fsPageToBlock(pFS, iOff), &iBlk);
  1292. *piRes = fsFirstPageOnBlock(pFS, iBlk) + iAdd - (iEob - iOff + 1);
  1293. return rc;
  1294. }
  1295. /*
  1296. ** If it is not already allocated, allocate either the FileSystem.aOBuffer (if
  1297. ** bWrite is true) or the FileSystem.aIBuffer (if bWrite is false). Return
  1298. ** LSM_OK if successful if the attempt to allocate memory fails.
  1299. */
  1300. static int fsAllocateBuffer(FileSystem *pFS, int bWrite){
  1301. u8 **pp; /* Pointer to either aIBuffer or aOBuffer */
  1302. assert( pFS->pCompress );
  1303. /* If neither buffer has been allocated, figure out how large they
  1304. ** should be. Store this value in FileSystem.nBuffer. */
  1305. if( pFS->nBuffer==0 ){
  1306. assert( pFS->aIBuffer==0 && pFS->aOBuffer==0 );
  1307. pFS->nBuffer = pFS->pCompress->xBound(pFS->pCompress->pCtx, pFS->nPagesize);
  1308. if( pFS->nBuffer<(pFS->szSector+6) ){
  1309. pFS->nBuffer = pFS->szSector+6;
  1310. }
  1311. }
  1312. pp = (bWrite ? &pFS->aOBuffer : &pFS->aIBuffer);
  1313. if( *pp==0 ){
  1314. *pp = lsmMalloc(pFS->pEnv, LSM_MAX(pFS->nBuffer, pFS->nPagesize));
  1315. if( *pp==0 ) return LSM_NOMEM_BKPT;
  1316. }
  1317. return LSM_OK;
  1318. }
  1319. /*
  1320. ** This function is only called in compressed database mode. It reads and
  1321. ** uncompresses the compressed data for page pPg from the database and
  1322. ** populates the pPg->aData[] buffer and pPg->nCompress field.
  1323. **
  1324. ** It is possible that instead of a page record, there is free space
  1325. ** at offset pPg->iPgno. In this case no data is read from the file, but
  1326. ** output variable *pnSpace is set to the total number of free bytes.
  1327. **
  1328. ** LSM_OK is returned if successful, or an LSM error code otherwise.
  1329. */
  1330. static int fsReadPagedata(
  1331. FileSystem *pFS, /* File-system handle */
  1332. Segment *pSeg, /* pPg is part of this segment */
  1333. Page *pPg, /* Page to read and uncompress data for */
  1334. int *pnSpace /* OUT: Total bytes of free space */
  1335. ){
  1336. lsm_compress *p = pFS->pCompress;
  1337. i64 iOff = pPg->iPg;
  1338. u8 aSz[3];
  1339. int rc;
  1340. assert( p && pPg->nCompress==0 );
  1341. if( fsAllocateBuffer(pFS, 0) ) return LSM_NOMEM;
  1342. rc = fsReadData(pFS, pSeg, iOff, aSz, sizeof(aSz));
  1343. if( rc==LSM_OK ){
  1344. int bFree;
  1345. if( aSz[0] & 0x80 ){
  1346. pPg->nCompress = (int)getRecordSize(aSz, &bFree);
  1347. }else{
  1348. pPg->nCompress = (int)aSz[0] - sizeof(aSz)*2;
  1349. bFree = 1;
  1350. }
  1351. if( bFree ){
  1352. if( pnSpace ){
  1353. *pnSpace = pPg->nCompress + sizeof(aSz)*2;
  1354. }else{
  1355. rc = LSM_CORRUPT_BKPT;
  1356. }
  1357. }else{
  1358. rc = fsAddOffset(pFS, pSeg, iOff, 3, &iOff);
  1359. if( rc==LSM_OK ){
  1360. if( pPg->nCompress>pFS->nBuffer ){
  1361. rc = LSM_CORRUPT_BKPT;
  1362. }else{
  1363. rc = fsReadData(pFS, pSeg, iOff, pFS->aIBuffer, pPg->nCompress);
  1364. }
  1365. if( rc==LSM_OK ){
  1366. int n = pFS->nPagesize;
  1367. rc = p->xUncompress(p->pCtx,
  1368. (char *)pPg->aData, &n,
  1369. (const char *)pFS->aIBuffer, pPg->nCompress
  1370. );
  1371. if( rc==LSM_OK && n!=pPg->pFS->nPagesize ){
  1372. rc = LSM_CORRUPT_BKPT;
  1373. }
  1374. }
  1375. }
  1376. }
  1377. }
  1378. return rc;
  1379. }
  1380. /*
  1381. ** Return a handle for a database page.
  1382. **
  1383. ** If this file-system object is accessing a compressed database it may be
  1384. ** that there is no page record at database file offset iPg. Instead, there
  1385. ** may be a free space record. In this case, set *ppPg to NULL and *pnSpace
  1386. ** to the total number of free bytes before returning.
  1387. **
  1388. ** If no error occurs, LSM_OK is returned. Otherwise, an lsm error code.
  1389. */
  1390. static int fsPageGet(
  1391. FileSystem *pFS, /* File-system handle */
  1392. Segment *pSeg, /* Block redirection to use (or NULL) */
  1393. LsmPgno iPg, /* Page id */
  1394. int noContent, /* True to not load content from disk */
  1395. Page **ppPg, /* OUT: New page handle */
  1396. int *pnSpace /* OUT: Bytes of free space */
  1397. ){
  1398. Page *p;
  1399. int iHash;
  1400. int rc = LSM_OK;
  1401. /* In most cases iReal is the same as iPg. Except, if pSeg->pRedirect is
  1402. ** not NULL, and the block containing iPg has been redirected, then iReal
  1403. ** is the page number after redirection. */
  1404. LsmPgno iReal = lsmFsRedirectPage(pFS, (pSeg ? pSeg->pRedirect : 0), iPg);
  1405. assert_lists_are_ok(pFS);
  1406. assert( iPg>=fsFirstPageOnBlock(pFS, 1) );
  1407. assert( iReal>=fsFirstPageOnBlock(pFS, 1) );
  1408. *ppPg = 0;
  1409. /* Search the hash-table for the page */
  1410. p = fsPageFindInHash(pFS, iReal, &iHash);
  1411. if( p ){
  1412. assert( p->flags & PAGE_FREE );
  1413. if( p->nRef==0 ) fsPageRemoveFromLru(pFS, p);
  1414. }else{
  1415. if( fsMmapPage(pFS, iReal) ){
  1416. i64 iEnd = (i64)iReal * pFS->nPagesize;
  1417. fsGrowMapping(pFS, iEnd, &rc);
  1418. if( rc!=LSM_OK ) return rc;
  1419. if( pFS->pFree ){
  1420. p = pFS->pFree;
  1421. pFS->pFree = p->pFreeNext;
  1422. assert( p->nRef==0 );
  1423. }else{
  1424. p = lsmMallocZeroRc(pFS->pEnv, sizeof(Page), &rc);
  1425. if( rc ) return rc;
  1426. p->pFS = pFS;
  1427. }
  1428. p->aData = &((u8 *)pFS->pMap)[pFS->nPagesize * (iReal-1)];
  1429. p->iPg = iReal;
  1430. /* This page now carries a pointer to the mapping. Link it in to
  1431. ** the FileSystem.pMapped list. */
  1432. assert( p->pMappedNext==0 );
  1433. p->pMappedNext = pFS->pMapped;
  1434. pFS->pMapped = p;
  1435. assert( pFS->pCompress==0 );
  1436. assert( (p->flags & PAGE_FREE)==0 );
  1437. }else{
  1438. rc = fsPageBuffer(pFS, &p);
  1439. if( rc==LSM_OK ){
  1440. int nSpace = 0;
  1441. p->iPg = iReal;
  1442. p->nRef = 0;
  1443. p->pFS = pFS;
  1444. assert( p->flags==0 || p->flags==PAGE_FREE );
  1445. #ifdef LSM_DEBUG
  1446. memset(p->aData, 0x56, pFS->nPagesize);
  1447. #endif
  1448. assert( p->pLruNext==0 && p->pLruPrev==0 );
  1449. if( noContent==0 ){
  1450. if( pFS->pCompress ){
  1451. rc = fsReadPagedata(pFS, pSeg, p, &nSpace);
  1452. }else{
  1453. int nByte = pFS->nPagesize;
  1454. i64 iOff = (i64)(iReal-1) * pFS->nPagesize;
  1455. rc = lsmEnvRead(pFS->pEnv, pFS->fdDb, iOff, p->aData, nByte);
  1456. }
  1457. pFS->nRead++;
  1458. }
  1459. /* If the xRead() call was successful (or not attempted), link the
  1460. ** page into the page-cache hash-table. Otherwise, if it failed,
  1461. ** free the buffer. */
  1462. if( rc==LSM_OK && nSpace==0 ){
  1463. p->pHashNext = pFS->apHash[iHash];
  1464. pFS->apHash[iHash] = p;
  1465. }else{
  1466. fsPageBufferFree(p);
  1467. p = 0;
  1468. if( pnSpace ) *pnSpace = nSpace;
  1469. }
  1470. }
  1471. }
  1472. assert( (rc==LSM_OK && (p || (pnSpace && *pnSpace)))
  1473. || (rc!=LSM_OK && p==0)
  1474. );
  1475. }
  1476. if( rc==LSM_OK && p ){
  1477. if( pFS->pCompress==0 && (fsIsLast(pFS, iReal) || fsIsFirst(pFS, iReal)) ){
  1478. p->nData = pFS->nPagesize - 4;
  1479. if( fsIsFirst(pFS, iReal) && p->nRef==0 ){
  1480. p->aData += 4;
  1481. p->flags |= PAGE_HASPREV;
  1482. }
  1483. }else{
  1484. p->nData = pFS->nPagesize;
  1485. }
  1486. pFS->nOut += (p->nRef==0);
  1487. p->nRef++;
  1488. }
  1489. *ppPg = p;
  1490. return rc;
  1491. }
  1492. /*
  1493. ** Read the 64-bit checkpoint id of the checkpoint currently stored on meta
  1494. ** page iMeta of the database file. If no error occurs, store the id value
  1495. ** in *piVal and return LSM_OK. Otherwise, return an LSM error code and leave
  1496. ** *piVal unmodified.
  1497. **
  1498. ** If a checkpointer connection is currently updating meta-page iMeta, or an
  1499. ** earlier checkpointer crashed while doing so, the value read into *piVal
  1500. ** may be garbage. It is the callers responsibility to deal with this.
  1501. */
  1502. int lsmFsReadSyncedId(lsm_db *db, int iMeta, i64 *piVal){
  1503. FileSystem *pFS = db->pFS;
  1504. int rc = LSM_OK;
  1505. assert( iMeta==1 || iMeta==2 );
  1506. if( pFS->nMapLimit>0 ){
  1507. fsGrowMapping(pFS, iMeta*LSM_META_PAGE_SIZE, &rc);
  1508. if( rc==LSM_OK ){
  1509. *piVal = (i64)lsmGetU64(&((u8 *)pFS->pMap)[(iMeta-1)*LSM_META_PAGE_SIZE]);
  1510. }
  1511. }else{
  1512. MetaPage *pMeta = 0;
  1513. rc = lsmFsMetaPageGet(pFS, 0, iMeta, &pMeta);
  1514. if( rc==LSM_OK ){
  1515. *piVal = (i64)lsmGetU64(pMeta->aData);
  1516. lsmFsMetaPageRelease(pMeta);
  1517. }
  1518. }
  1519. return rc;
  1520. }
  1521. /*
  1522. ** Return true if the first or last page of segment pRun falls between iFirst
  1523. ** and iLast, inclusive, and pRun is not equal to pIgnore.
  1524. */
  1525. static int fsRunEndsBetween(
  1526. Segment *pRun,
  1527. Segment *pIgnore,
  1528. LsmPgno iFirst,
  1529. LsmPgno iLast
  1530. ){
  1531. return (pRun!=pIgnore && (
  1532. (pRun->iFirst>=iFirst && pRun->iFirst<=iLast)
  1533. || (pRun->iLastPg>=iFirst && pRun->iLastPg<=iLast)
  1534. ));
  1535. }
  1536. /*
  1537. ** Return true if level pLevel contains a segment other than pIgnore for
  1538. ** which the first or last page is between iFirst and iLast, inclusive.
  1539. */
  1540. static int fsLevelEndsBetween(
  1541. Level *pLevel,
  1542. Segment *pIgnore,
  1543. LsmPgno iFirst,
  1544. LsmPgno iLast
  1545. ){
  1546. int i;
  1547. if( fsRunEndsBetween(&pLevel->lhs, pIgnore, iFirst, iLast) ){
  1548. return 1;
  1549. }
  1550. for(i=0; i<pLevel->nRight; i++){
  1551. if( fsRunEndsBetween(&pLevel->aRhs[i], pIgnore, iFirst, iLast) ){
  1552. return 1;
  1553. }
  1554. }
  1555. return 0;
  1556. }
  1557. /*
  1558. ** Block iBlk is no longer in use by segment pIgnore. If it is not in use
  1559. ** by any other segment, move it to the free block list.
  1560. */
  1561. static int fsFreeBlock(
  1562. FileSystem *pFS, /* File system object */
  1563. Snapshot *pSnapshot, /* Worker snapshot */
  1564. Segment *pIgnore, /* Ignore this run when searching */
  1565. int iBlk /* Block number of block to free */
  1566. ){
  1567. int rc = LSM_OK; /* Return code */
  1568. LsmPgno iFirst; /* First page on block iBlk */
  1569. LsmPgno iLast; /* Last page on block iBlk */
  1570. Level *pLevel; /* Used to iterate through levels */
  1571. int iIn; /* Used to iterate through append points */
  1572. int iOut = 0; /* Used to output append points */
  1573. LsmPgno *aApp = pSnapshot->aiAppend;
  1574. iFirst = fsFirstPageOnBlock(pFS, iBlk);
  1575. iLast = fsLastPageOnBlock(pFS, iBlk);
  1576. /* Check if any other run in the snapshot has a start or end page
  1577. ** within this block. If there is such a run, return early. */
  1578. for(pLevel=lsmDbSnapshotLevel(pSnapshot); pLevel; pLevel=pLevel->pNext){
  1579. if( fsLevelEndsBetween(pLevel, pIgnore, iFirst, iLast) ){
  1580. return LSM_OK;
  1581. }
  1582. }
  1583. /* Remove any entries that lie on this block from the append-list. */
  1584. for(iIn=0; iIn<LSM_APPLIST_SZ; iIn++){
  1585. if( aApp[iIn]<iFirst || aApp[iIn]>iLast ){
  1586. aApp[iOut++] = aApp[iIn];
  1587. }
  1588. }
  1589. while( iOut<LSM_APPLIST_SZ ) aApp[iOut++] = 0;
  1590. if( rc==LSM_OK ){
  1591. rc = lsmBlockFree(pFS->pDb, iBlk);
  1592. }
  1593. return rc;
  1594. }
  1595. /*
  1596. ** Delete or otherwise recycle the blocks currently occupied by run pDel.
  1597. */
  1598. int lsmFsSortedDelete(
  1599. FileSystem *pFS,
  1600. Snapshot *pSnapshot,
  1601. int bZero, /* True to zero the Segment structure */
  1602. Segment *pDel
  1603. ){
  1604. if( pDel->iFirst ){
  1605. int rc = LSM_OK;
  1606. int iBlk;
  1607. int iLastBlk;
  1608. iBlk = fsPageToBlock(pFS, pDel->iFirst);
  1609. iLastBlk = fsPageToBlock(pFS, pDel->iLastPg);
  1610. /* Mark all blocks currently used by this sorted run as free */
  1611. while( iBlk && rc==LSM_OK ){
  1612. int iNext = 0;
  1613. if( iBlk!=iLastBlk ){
  1614. rc = fsBlockNext(pFS, pDel, iBlk, &iNext);
  1615. }else if( bZero==0 && pDel->iLastPg!=fsLastPageOnBlock(pFS, iLastBlk) ){
  1616. break;
  1617. }
  1618. rc = fsFreeBlock(pFS, pSnapshot, pDel, iBlk);
  1619. iBlk = iNext;
  1620. }
  1621. if( pDel->pRedirect ){
  1622. assert( pDel->pRedirect==&pSnapshot->redirect );
  1623. pSnapshot->redirect.n = 0;
  1624. }
  1625. if( bZero ) memset(pDel, 0, sizeof(Segment));
  1626. }
  1627. return LSM_OK;
  1628. }
  1629. /*
  1630. ** aPgno is an array containing nPgno page numbers. Return the smallest page
  1631. ** number from the array that falls on block iBlk. Or, if none of the pages
  1632. ** in aPgno[] fall on block iBlk, return 0.
  1633. */
  1634. static LsmPgno firstOnBlock(
  1635. FileSystem *pFS,
  1636. int iBlk,
  1637. LsmPgno *aPgno,
  1638. int nPgno
  1639. ){
  1640. LsmPgno iRet = 0;
  1641. int i;
  1642. for(i=0; i<nPgno; i++){
  1643. LsmPgno iPg = aPgno[i];
  1644. if( fsPageToBlock(pFS, iPg)==iBlk && (iRet==0 || iPg<iRet) ){
  1645. iRet = iPg;
  1646. }
  1647. }
  1648. return iRet;
  1649. }
  1650. #ifndef NDEBUG
  1651. /*
  1652. ** Return true if page iPg, which is a part of segment p, lies on
  1653. ** a redirected block.
  1654. */
  1655. static int fsPageRedirects(FileSystem *pFS, Segment *p, LsmPgno iPg){
  1656. return (iPg!=0 && iPg!=lsmFsRedirectPage(pFS, p->pRedirect, iPg));
  1657. }
  1658. /*
  1659. ** Return true if the second argument is not NULL and any of the first
  1660. ** last or root pages lie on a redirected block.
  1661. */
  1662. static int fsSegmentRedirects(FileSystem *pFS, Segment *p){
  1663. return (p && (
  1664. fsPageRedirects(pFS, p, p->iFirst)
  1665. || fsPageRedirects(pFS, p, p->iRoot)
  1666. || fsPageRedirects(pFS, p, p->iLastPg)
  1667. ));
  1668. }
  1669. #endif
  1670. /*
  1671. ** Argument aPgno is an array of nPgno page numbers. All pages belong to
  1672. ** the segment pRun. This function gobbles from the start of the run to the
  1673. ** first page that appears in aPgno[] (i.e. so that the aPgno[] entry is
  1674. ** the new first page of the run).
  1675. */
  1676. void lsmFsGobble(
  1677. lsm_db *pDb,
  1678. Segment *pRun,
  1679. LsmPgno *aPgno,
  1680. int nPgno
  1681. ){
  1682. int rc = LSM_OK;
  1683. FileSystem *pFS = pDb->pFS;
  1684. Snapshot *pSnapshot = pDb->pWorker;
  1685. int iBlk;
  1686. assert( pRun->nSize>0 );
  1687. assert( 0==fsSegmentRedirects(pFS, pRun) );
  1688. assert( nPgno>0 && 0==fsPageRedirects(pFS, pRun, aPgno[0]) );
  1689. iBlk = fsPageToBlock(pFS, pRun->iFirst);
  1690. pRun->nSize += (pRun->iFirst - fsFirstPageOnBlock(pFS, iBlk));
  1691. while( rc==LSM_OK ){
  1692. int iNext = 0;
  1693. LsmPgno iFirst = firstOnBlock(pFS, iBlk, aPgno, nPgno);
  1694. if( iFirst ){
  1695. pRun->iFirst = iFirst;
  1696. break;
  1697. }
  1698. rc = fsBlockNext(pFS, pRun, iBlk, &iNext);
  1699. if( rc==LSM_OK ) rc = fsFreeBlock(pFS, pSnapshot, pRun, iBlk);
  1700. pRun->nSize -= (
  1701. 1 + fsLastPageOnBlock(pFS, iBlk) - fsFirstPageOnBlock(pFS, iBlk)
  1702. );
  1703. iBlk = iNext;
  1704. }
  1705. pRun->nSize -= (pRun->iFirst - fsFirstPageOnBlock(pFS, iBlk));
  1706. assert( pRun->nSize>0 );
  1707. }
  1708. /*
  1709. ** This function is only used in compressed database mode.
  1710. **
  1711. ** Argument iPg is the page number (byte offset) of a page within segment
  1712. ** pSeg. The page record, including all headers, is nByte bytes in size.
  1713. ** Before returning, set *piNext to the page number of the next page in
  1714. ** the segment, or to zero if iPg is the last.
  1715. **
  1716. ** In other words, do:
  1717. **
  1718. ** *piNext = iPg + nByte;
  1719. **
  1720. ** But take block overflow and redirection into account.
  1721. */
  1722. static int fsNextPageOffset(
  1723. FileSystem *pFS, /* File system object */
  1724. Segment *pSeg, /* Segment to move within */
  1725. LsmPgno iPg, /* Offset of current page */
  1726. int nByte, /* Size of current page including headers */
  1727. LsmPgno *piNext /* OUT: Offset of next page. Or zero (EOF) */
  1728. ){
  1729. LsmPgno iNext;
  1730. int rc;
  1731. assert( pFS->pCompress );
  1732. rc = fsAddOffset(pFS, pSeg, iPg, nByte-1, &iNext);
  1733. if( pSeg && iNext==pSeg->iLastPg ){
  1734. iNext = 0;
  1735. }else if( rc==LSM_OK ){
  1736. rc = fsAddOffset(pFS, pSeg, iNext, 1, &iNext);
  1737. }
  1738. *piNext = iNext;
  1739. return rc;
  1740. }
  1741. /*
  1742. ** This function is only used in compressed database mode.
  1743. **
  1744. ** Argument iPg is the page number of a pagethat appears in segment pSeg.
  1745. ** This function determines the page number of the previous page in the
  1746. ** same run. *piPrev is set to the previous page number before returning.
  1747. **
  1748. ** LSM_OK is returned if no error occurs. Otherwise, an lsm error code.
  1749. ** If any value other than LSM_OK is returned, then the final value of
  1750. ** *piPrev is undefined.
  1751. */
  1752. static int fsGetPageBefore(
  1753. FileSystem *pFS,
  1754. Segment *pSeg,
  1755. LsmPgno iPg,
  1756. LsmPgno *piPrev
  1757. ){
  1758. u8 aSz[3];
  1759. int rc;
  1760. i64 iRead;
  1761. assert( pFS->pCompress );
  1762. rc = fsSubtractOffset(pFS, pSeg, iPg, sizeof(aSz), &iRead);
  1763. if( rc==LSM_OK ) rc = fsReadData(pFS, pSeg, iRead, aSz, sizeof(aSz));
  1764. if( rc==LSM_OK ){
  1765. int bFree;
  1766. int nSz;
  1767. if( aSz[2] & 0x80 ){
  1768. nSz = getRecordSize(aSz, &bFree) + sizeof(aSz)*2;
  1769. }else{
  1770. nSz = (int)(aSz[2] & 0x7F);
  1771. bFree = 1;
  1772. }
  1773. rc = fsSubtractOffset(pFS, pSeg, iPg, nSz, piPrev);
  1774. }
  1775. return rc;
  1776. }
  1777. /*
  1778. ** The first argument to this function is a valid reference to a database
  1779. ** file page that is part of a sorted run. If parameter eDir is -1, this
  1780. ** function attempts to locate and load the previous page in the same run.
  1781. ** Or, if eDir is +1, it attempts to find the next page in the same run.
  1782. ** The results of passing an eDir value other than positive or negative one
  1783. ** are undefined.
  1784. **
  1785. ** If parameter pRun is not NULL then it must point to the run that page
  1786. ** pPg belongs to. In this case, if pPg is the first or last page of the
  1787. ** run, and the request is for the previous or next page, respectively,
  1788. ** *ppNext is set to NULL before returning LSM_OK. If pRun is NULL, then it
  1789. ** is assumed that the next or previous page, as requested, exists.
  1790. **
  1791. ** If the previous/next page does exist and is successfully loaded, *ppNext
  1792. ** is set to point to it and LSM_OK is returned. Otherwise, if an error
  1793. ** occurs, *ppNext is set to NULL and and lsm error code returned.
  1794. **
  1795. ** Page references returned by this function should be released by the
  1796. ** caller using lsmFsPageRelease().
  1797. */
  1798. int lsmFsDbPageNext(Segment *pRun, Page *pPg, int eDir, Page **ppNext){
  1799. int rc = LSM_OK;
  1800. FileSystem *pFS = pPg->pFS;
  1801. LsmPgno iPg = pPg->iPg;
  1802. assert( 0==fsSegmentRedirects(pFS, pRun) );
  1803. if( pFS->pCompress ){
  1804. int nSpace = pPg->nCompress + 2*3;
  1805. do {
  1806. if( eDir>0 ){
  1807. rc = fsNextPageOffset(pFS, pRun, iPg, nSpace, &iPg);
  1808. }else{
  1809. if( iPg==pRun->iFirst ){
  1810. iPg = 0;
  1811. }else{
  1812. rc = fsGetPageBefore(pFS, pRun, iPg, &iPg);
  1813. }
  1814. }
  1815. nSpace = 0;
  1816. if( iPg!=0 ){
  1817. rc = fsPageGet(pFS, pRun, iPg, 0, ppNext, &nSpace);
  1818. assert( (*ppNext==0)==(rc!=LSM_OK || nSpace>0) );
  1819. }else{
  1820. *ppNext = 0;
  1821. }
  1822. }while( nSpace>0 && rc==LSM_OK );
  1823. }else{
  1824. Redirect *pRedir = pRun ? pRun->pRedirect : 0;
  1825. assert( eDir==1 || eDir==-1 );
  1826. if( eDir<0 ){
  1827. if( pRun && iPg==pRun->iFirst ){
  1828. *ppNext = 0;
  1829. return LSM_OK;
  1830. }else if( fsIsFirst(pFS, iPg) ){
  1831. assert( pPg->flags & PAGE_HASPREV );
  1832. iPg = fsLastPageOnBlock(pFS, lsmGetU32(&pPg->aData[-4]));
  1833. }else{
  1834. iPg--;
  1835. }
  1836. }else{
  1837. if( pRun ){
  1838. if( iPg==pRun->iLastPg ){
  1839. *ppNext = 0;
  1840. return LSM_OK;
  1841. }
  1842. }
  1843. if( fsIsLast(pFS, iPg) ){
  1844. int iBlk = fsRedirectBlock(
  1845. pRedir, lsmGetU32(&pPg->aData[pFS->nPagesize-4])
  1846. );
  1847. iPg = fsFirstPageOnBlock(pFS, iBlk);
  1848. }else{
  1849. iPg++;
  1850. }
  1851. }
  1852. rc = fsPageGet(pFS, pRun, iPg, 0, ppNext, 0);
  1853. }
  1854. return rc;
  1855. }
  1856. /*
  1857. ** This function is called when creating a new segment to determine if the
  1858. ** first part of it can be written following an existing segment on an
  1859. ** already allocated block. If it is possible, the page number of the first
  1860. ** page to use for the new segment is returned. Otherwise zero.
  1861. **
  1862. ** If argument pLvl is not NULL, then this function will not attempt to
  1863. ** start the new segment immediately following any segment that is part
  1864. ** of the right-hand-side of pLvl.
  1865. */
  1866. static LsmPgno findAppendPoint(FileSystem *pFS, Level *pLvl){
  1867. int i;
  1868. LsmPgno *aiAppend = pFS->pDb->pWorker->aiAppend;
  1869. LsmPgno iRet = 0;
  1870. for(i=LSM_APPLIST_SZ-1; iRet==0 && i>=0; i--){
  1871. if( (iRet = aiAppend[i]) ){
  1872. if( pLvl ){
  1873. int iBlk = fsPageToBlock(pFS, iRet);
  1874. int j;
  1875. for(j=0; iRet && j<pLvl->nRight; j++){
  1876. if( fsPageToBlock(pFS, pLvl->aRhs[j].iLastPg)==iBlk ){
  1877. iRet = 0;
  1878. }
  1879. }
  1880. }
  1881. if( iRet ) aiAppend[i] = 0;
  1882. }
  1883. }
  1884. return iRet;
  1885. }
  1886. /*
  1887. ** Append a page to the left-hand-side of pLvl. Set the ref-count to 1 and
  1888. ** return a pointer to it. The page is writable until either
  1889. ** lsmFsPagePersist() is called on it or the ref-count drops to zero.
  1890. */
  1891. int lsmFsSortedAppend(
  1892. FileSystem *pFS,
  1893. Snapshot *pSnapshot,
  1894. Level *pLvl,
  1895. int bDefer,
  1896. Page **ppOut
  1897. ){
  1898. int rc = LSM_OK;
  1899. Page *pPg = 0;
  1900. LsmPgno iApp = 0;
  1901. LsmPgno iNext = 0;
  1902. Segment *p = &pLvl->lhs;
  1903. LsmPgno iPrev = p->iLastPg;
  1904. *ppOut = 0;
  1905. assert( p->pRedirect==0 );
  1906. if( pFS->pCompress || bDefer ){
  1907. /* In compressed database mode the page is not assigned a page number
  1908. ** or location in the database file at this point. This will be done
  1909. ** by the lsmFsPagePersist() call. */
  1910. rc = fsPageBuffer(pFS, &pPg);
  1911. if( rc==LSM_OK ){
  1912. pPg->pFS = pFS;
  1913. pPg->pSeg = p;
  1914. pPg->iPg = 0;
  1915. pPg->flags |= PAGE_DIRTY;
  1916. pPg->nData = pFS->nPagesize;
  1917. assert( pPg->aData );
  1918. if( pFS->pCompress==0 ) pPg->nData -= 4;
  1919. pPg->nRef = 1;
  1920. pFS->nOut++;
  1921. }
  1922. }else{
  1923. if( iPrev==0 ){
  1924. iApp = findAppendPoint(pFS, pLvl);
  1925. }else if( fsIsLast(pFS, iPrev) ){
  1926. int iNext2;
  1927. rc = fsBlockNext(pFS, 0, fsPageToBlock(pFS, iPrev), &iNext2);
  1928. if( rc!=LSM_OK ) return rc;
  1929. iApp = fsFirstPageOnBlock(pFS, iNext2);
  1930. }else{
  1931. iApp = iPrev + 1;
  1932. }
  1933. /* If this is the first page allocated, or if the page allocated is the
  1934. ** last in the block, also allocate the next block here. */
  1935. if( iApp==0 || fsIsLast(pFS, iApp) ){
  1936. int iNew; /* New block number */
  1937. rc = lsmBlockAllocate(pFS->pDb, 0, &iNew);
  1938. if( rc!=LSM_OK ) return rc;
  1939. if( iApp==0 ){
  1940. iApp = fsFirstPageOnBlock(pFS, iNew);
  1941. }else{
  1942. iNext = fsFirstPageOnBlock(pFS, iNew);
  1943. }
  1944. }
  1945. /* Grab the new page. */
  1946. pPg = 0;
  1947. rc = fsPageGet(pFS, 0, iApp, 1, &pPg, 0);
  1948. assert( rc==LSM_OK || pPg==0 );
  1949. /* If this is the first or last page of a block, fill in the pointer
  1950. ** value at the end of the new page. */
  1951. if( rc==LSM_OK ){
  1952. p->nSize++;
  1953. p->iLastPg = iApp;
  1954. if( p->iFirst==0 ) p->iFirst = iApp;
  1955. pPg->flags |= PAGE_DIRTY;
  1956. if( fsIsLast(pFS, iApp) ){
  1957. lsmPutU32(&pPg->aData[pFS->nPagesize-4], fsPageToBlock(pFS, iNext));
  1958. }else if( fsIsFirst(pFS, iApp) ){
  1959. lsmPutU32(&pPg->aData[-4], fsPageToBlock(pFS, iPrev));
  1960. }
  1961. }
  1962. }
  1963. *ppOut = pPg;
  1964. return rc;
  1965. }
  1966. /*
  1967. ** Mark the segment passed as the second argument as finished. Once a segment
  1968. ** is marked as finished it is not possible to append any further pages to
  1969. ** it.
  1970. **
  1971. ** Return LSM_OK if successful or an lsm error code if an error occurs.
  1972. */
  1973. int lsmFsSortedFinish(FileSystem *pFS, Segment *p){
  1974. int rc = LSM_OK;
  1975. if( p && p->iLastPg ){
  1976. assert( p->pRedirect==0 );
  1977. /* Check if the last page of this run happens to be the last of a block.
  1978. ** If it is, then an extra block has already been allocated for this run.
  1979. ** Shift this extra block back to the free-block list.
  1980. **
  1981. ** Otherwise, add the first free page in the last block used by the run
  1982. ** to the lAppend list.
  1983. */
  1984. if( fsLastPageOnPagesBlock(pFS, p->iLastPg)!=p->iLastPg ){
  1985. int i;
  1986. LsmPgno *aiAppend = pFS->pDb->pWorker->aiAppend;
  1987. for(i=0; i<LSM_APPLIST_SZ; i++){
  1988. if( aiAppend[i]==0 ){
  1989. aiAppend[i] = p->iLastPg+1;
  1990. break;
  1991. }
  1992. }
  1993. }else if( pFS->pCompress==0 ){
  1994. Page *pLast;
  1995. rc = fsPageGet(pFS, 0, p->iLastPg, 0, &pLast, 0);
  1996. if( rc==LSM_OK ){
  1997. int iBlk = (int)lsmGetU32(&pLast->aData[pFS->nPagesize-4]);
  1998. lsmBlockRefree(pFS->pDb, iBlk);
  1999. lsmFsPageRelease(pLast);
  2000. }
  2001. }else{
  2002. int iBlk = 0;
  2003. rc = fsBlockNext(pFS, p, fsPageToBlock(pFS, p->iLastPg), &iBlk);
  2004. if( rc==LSM_OK ){
  2005. lsmBlockRefree(pFS->pDb, iBlk);
  2006. }
  2007. }
  2008. }
  2009. return rc;
  2010. }
  2011. /*
  2012. ** Obtain a reference to page number iPg.
  2013. **
  2014. ** Return LSM_OK if successful, or an lsm error code if an error occurs.
  2015. */
  2016. int lsmFsDbPageGet(FileSystem *pFS, Segment *pSeg, LsmPgno iPg, Page **ppPg){
  2017. return fsPageGet(pFS, pSeg, iPg, 0, ppPg, 0);
  2018. }
  2019. /*
  2020. ** Obtain a reference to the last page in the segment passed as the
  2021. ** second argument.
  2022. **
  2023. ** Return LSM_OK if successful, or an lsm error code if an error occurs.
  2024. */
  2025. int lsmFsDbPageLast(FileSystem *pFS, Segment *pSeg, Page **ppPg){
  2026. int rc;
  2027. LsmPgno iPg = pSeg->iLastPg;
  2028. if( pFS->pCompress ){
  2029. int nSpace;
  2030. iPg++;
  2031. do {
  2032. nSpace = 0;
  2033. rc = fsGetPageBefore(pFS, pSeg, iPg, &iPg);
  2034. if( rc==LSM_OK ){
  2035. rc = fsPageGet(pFS, pSeg, iPg, 0, ppPg, &nSpace);
  2036. }
  2037. }while( rc==LSM_OK && nSpace>0 );
  2038. }else{
  2039. rc = fsPageGet(pFS, pSeg, iPg, 0, ppPg, 0);
  2040. }
  2041. return rc;
  2042. }
  2043. /*
  2044. ** Return a reference to meta-page iPg. If successful, LSM_OK is returned
  2045. ** and *ppPg populated with the new page reference. The reference should
  2046. ** be released by the caller using lsmFsPageRelease().
  2047. **
  2048. ** Otherwise, if an error occurs, *ppPg is set to NULL and an LSM error
  2049. ** code is returned.
  2050. */
  2051. int lsmFsMetaPageGet(
  2052. FileSystem *pFS, /* File-system connection */
  2053. int bWrite, /* True for write access, false for read */
  2054. int iPg, /* Either 1 or 2 */
  2055. MetaPage **ppPg /* OUT: Pointer to MetaPage object */
  2056. ){
  2057. int rc = LSM_OK;
  2058. MetaPage *pPg;
  2059. assert( iPg==1 || iPg==2 );
  2060. pPg = lsmMallocZeroRc(pFS->pEnv, sizeof(Page), &rc);
  2061. if( pPg ){
  2062. i64 iOff = (iPg-1) * pFS->nMetasize;
  2063. if( pFS->nMapLimit>0 ){
  2064. fsGrowMapping(pFS, 2*pFS->nMetasize, &rc);
  2065. pPg->aData = (u8 *)(pFS->pMap) + iOff;
  2066. }else{
  2067. pPg->aData = lsmMallocRc(pFS->pEnv, pFS->nMetasize, &rc);
  2068. if( rc==LSM_OK && bWrite==0 ){
  2069. rc = lsmEnvRead(
  2070. pFS->pEnv, pFS->fdDb, iOff, pPg->aData, pFS->nMetaRwSize
  2071. );
  2072. }
  2073. #ifndef NDEBUG
  2074. /* pPg->aData causes an uninitialized access via a downstream write().
  2075. After discussion on this list, this memory should not, for performance
  2076. reasons, be memset. However, tracking down "real" misuse is more
  2077. difficult with this "false" positive, so it is set when NDEBUG.
  2078. */
  2079. else if( rc==LSM_OK ){
  2080. memset( pPg->aData, 0x77, pFS->nMetasize );
  2081. }
  2082. #endif
  2083. }
  2084. if( rc!=LSM_OK ){
  2085. if( pFS->nMapLimit==0 ) lsmFree(pFS->pEnv, pPg->aData);
  2086. lsmFree(pFS->pEnv, pPg);
  2087. pPg = 0;
  2088. }else{
  2089. pPg->iPg = iPg;
  2090. pPg->bWrite = bWrite;
  2091. pPg->pFS = pFS;
  2092. }
  2093. }
  2094. *ppPg = pPg;
  2095. return rc;
  2096. }
  2097. /*
  2098. ** Release a meta-page reference obtained via a call to lsmFsMetaPageGet().
  2099. */
  2100. int lsmFsMetaPageRelease(MetaPage *pPg){
  2101. int rc = LSM_OK;
  2102. if( pPg ){
  2103. FileSystem *pFS = pPg->pFS;
  2104. if( pFS->nMapLimit==0 ){
  2105. if( pPg->bWrite ){
  2106. i64 iOff = (pPg->iPg==2 ? pFS->nMetasize : 0);
  2107. int nWrite = pFS->nMetaRwSize;
  2108. rc = lsmEnvWrite(pFS->pEnv, pFS->fdDb, iOff, pPg->aData, nWrite);
  2109. }
  2110. lsmFree(pFS->pEnv, pPg->aData);
  2111. }
  2112. lsmFree(pFS->pEnv, pPg);
  2113. }
  2114. return rc;
  2115. }
  2116. /*
  2117. ** Return a pointer to a buffer containing the data associated with the
  2118. ** meta-page passed as the first argument. If parameter pnData is not NULL,
  2119. ** set *pnData to the size of the meta-page in bytes before returning.
  2120. */
  2121. u8 *lsmFsMetaPageData(MetaPage *pPg, int *pnData){
  2122. if( pnData ) *pnData = pPg->pFS->nMetaRwSize;
  2123. return pPg->aData;
  2124. }
  2125. /*
  2126. ** Return true if page is currently writable. This is used in assert()
  2127. ** statements only.
  2128. */
  2129. #ifndef NDEBUG
  2130. int lsmFsPageWritable(Page *pPg){
  2131. return (pPg->flags & PAGE_DIRTY) ? 1 : 0;
  2132. }
  2133. #endif
  2134. /*
  2135. ** This is called when block iFrom is being redirected to iTo. If page
  2136. ** number (*piPg) lies on block iFrom, then calculate the equivalent
  2137. ** page on block iTo and set *piPg to this value before returning.
  2138. */
  2139. static void fsMovePage(
  2140. FileSystem *pFS, /* File system object */
  2141. int iTo, /* Destination block */
  2142. int iFrom, /* Source block */
  2143. LsmPgno *piPg /* IN/OUT: Page number */
  2144. ){
  2145. LsmPgno iPg = *piPg;
  2146. if( iFrom==fsPageToBlock(pFS, iPg) ){
  2147. const int nPagePerBlock = (
  2148. pFS->pCompress ? pFS ->nBlocksize : (pFS->nBlocksize / pFS->nPagesize)
  2149. );
  2150. *piPg = iPg - (LsmPgno)(iFrom - iTo) * nPagePerBlock;
  2151. }
  2152. }
  2153. /*
  2154. ** Copy the contents of block iFrom to block iTo.
  2155. **
  2156. ** It is safe to assume that there are no outstanding references to pages
  2157. ** on block iTo. And that block iFrom is not currently being written. In
  2158. ** other words, the data can be read and written directly.
  2159. */
  2160. int lsmFsMoveBlock(FileSystem *pFS, Segment *pSeg, int iTo, int iFrom){
  2161. Snapshot *p = pFS->pDb->pWorker;
  2162. int rc = LSM_OK;
  2163. int i;
  2164. i64 nMap;
  2165. i64 iFromOff = (i64)(iFrom-1) * pFS->nBlocksize;
  2166. i64 iToOff = (i64)(iTo-1) * pFS->nBlocksize;
  2167. assert( iTo!=1 );
  2168. assert( iFrom>iTo );
  2169. /* Grow the mapping as required. */
  2170. nMap = LSM_MIN(pFS->nMapLimit, (i64)iFrom * pFS->nBlocksize);
  2171. fsGrowMapping(pFS, nMap, &rc);
  2172. if( rc==LSM_OK ){
  2173. const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
  2174. int nSz = pFS->nPagesize;
  2175. u8 *aBuf = 0;
  2176. u8 *aData = 0;
  2177. for(i=0; rc==LSM_OK && i<nPagePerBlock; i++){
  2178. i64 iOff = iFromOff + i*nSz;
  2179. /* Set aData to point to a buffer containing the from page */
  2180. if( (iOff+nSz)<=pFS->nMapLimit ){
  2181. u8 *aMap = (u8 *)(pFS->pMap);
  2182. aData = &aMap[iOff];
  2183. }else{
  2184. if( aBuf==0 ){
  2185. aBuf = (u8 *)lsmMallocRc(pFS->pEnv, nSz, &rc);
  2186. if( aBuf==0 ) break;
  2187. }
  2188. aData = aBuf;
  2189. rc = lsmEnvRead(pFS->pEnv, pFS->fdDb, iOff, aData, nSz);
  2190. }
  2191. /* Copy aData to the to page */
  2192. if( rc==LSM_OK ){
  2193. iOff = iToOff + i*nSz;
  2194. if( (iOff+nSz)<=pFS->nMapLimit ){
  2195. u8 *aMap = (u8 *)(pFS->pMap);
  2196. memcpy(&aMap[iOff], aData, nSz);
  2197. }else{
  2198. rc = lsmEnvWrite(pFS->pEnv, pFS->fdDb, iOff, aData, nSz);
  2199. }
  2200. }
  2201. }
  2202. lsmFree(pFS->pEnv, aBuf);
  2203. lsmFsPurgeCache(pFS);
  2204. }
  2205. /* Update append-point list if necessary */
  2206. for(i=0; i<LSM_APPLIST_SZ; i++){
  2207. fsMovePage(pFS, iTo, iFrom, &p->aiAppend[i]);
  2208. }
  2209. /* Update the Segment structure itself */
  2210. fsMovePage(pFS, iTo, iFrom, &pSeg->iFirst);
  2211. fsMovePage(pFS, iTo, iFrom, &pSeg->iLastPg);
  2212. fsMovePage(pFS, iTo, iFrom, &pSeg->iRoot);
  2213. return rc;
  2214. }
  2215. /*
  2216. ** Append raw data to a segment. Return the database file offset that the
  2217. ** data is written to (this may be used as the page number if the data
  2218. ** being appended is a new page record).
  2219. **
  2220. ** This function is only used in compressed database mode.
  2221. */
  2222. static LsmPgno fsAppendData(
  2223. FileSystem *pFS, /* File-system handle */
  2224. Segment *pSeg, /* Segment to append to */
  2225. const u8 *aData, /* Buffer containing data to write */
  2226. int nData, /* Size of buffer aData[] in bytes */
  2227. int *pRc /* IN/OUT: Error code */
  2228. ){
  2229. LsmPgno iRet = 0;
  2230. int rc = *pRc;
  2231. assert( pFS->pCompress );
  2232. if( rc==LSM_OK ){
  2233. int nRem = 0;
  2234. int nWrite = 0;
  2235. LsmPgno iLastOnBlock;
  2236. LsmPgno iApp = pSeg->iLastPg+1;
  2237. /* If this is the first data written into the segment, find an append-point
  2238. ** or allocate a new block. */
  2239. if( iApp==1 ){
  2240. pSeg->iFirst = iApp = findAppendPoint(pFS, 0);
  2241. if( iApp==0 ){
  2242. int iBlk;
  2243. rc = lsmBlockAllocate(pFS->pDb, 0, &iBlk);
  2244. pSeg->iFirst = iApp = fsFirstPageOnBlock(pFS, iBlk);
  2245. }
  2246. }
  2247. iRet = iApp;
  2248. /* Write as much data as is possible at iApp (usually all of it). */
  2249. iLastOnBlock = fsLastPageOnPagesBlock(pFS, iApp);
  2250. if( rc==LSM_OK ){
  2251. int nSpace = (int)(iLastOnBlock - iApp + 1);
  2252. nWrite = LSM_MIN(nData, nSpace);
  2253. nRem = nData - nWrite;
  2254. assert( nWrite>=0 );
  2255. if( nWrite!=0 ){
  2256. rc = lsmEnvWrite(pFS->pEnv, pFS->fdDb, iApp, aData, nWrite);
  2257. }
  2258. iApp += nWrite;
  2259. }
  2260. /* If required, allocate a new block and write the rest of the data
  2261. ** into it. Set the next and previous block pointers to link the new
  2262. ** block to the old. */
  2263. assert( nRem<=0 || (iApp-1)==iLastOnBlock );
  2264. if( rc==LSM_OK && (iApp-1)==iLastOnBlock ){
  2265. u8 aPtr[4]; /* Space to serialize a u32 */
  2266. int iBlk; /* New block number */
  2267. if( nWrite>0 ){
  2268. /* Allocate a new block. */
  2269. rc = lsmBlockAllocate(pFS->pDb, 0, &iBlk);
  2270. /* Set the "next" pointer on the old block */
  2271. if( rc==LSM_OK ){
  2272. assert( iApp==(fsPageToBlock(pFS, iApp)*pFS->nBlocksize)-4 );
  2273. lsmPutU32(aPtr, iBlk);
  2274. rc = lsmEnvWrite(pFS->pEnv, pFS->fdDb, iApp, aPtr, sizeof(aPtr));
  2275. }
  2276. /* Set the "prev" pointer on the new block */
  2277. if( rc==LSM_OK ){
  2278. LsmPgno iWrite;
  2279. lsmPutU32(aPtr, fsPageToBlock(pFS, iApp));
  2280. iWrite = fsFirstPageOnBlock(pFS, iBlk);
  2281. rc = lsmEnvWrite(pFS->pEnv, pFS->fdDb, iWrite-4, aPtr, sizeof(aPtr));
  2282. if( nRem>0 ) iApp = iWrite;
  2283. }
  2284. }else{
  2285. /* The next block is already allocated. */
  2286. assert( nRem>0 );
  2287. assert( pSeg->pRedirect==0 );
  2288. rc = fsBlockNext(pFS, 0, fsPageToBlock(pFS, iApp), &iBlk);
  2289. iRet = iApp = fsFirstPageOnBlock(pFS, iBlk);
  2290. }
  2291. /* Write the remaining data into the new block */
  2292. if( rc==LSM_OK && nRem>0 ){
  2293. rc = lsmEnvWrite(pFS->pEnv, pFS->fdDb, iApp, &aData[nWrite], nRem);
  2294. iApp += nRem;
  2295. }
  2296. }
  2297. pSeg->iLastPg = iApp-1;
  2298. *pRc = rc;
  2299. }
  2300. return iRet;
  2301. }
  2302. /*
  2303. ** This function is only called in compressed database mode. It
  2304. ** compresses the contents of page pPg and writes the result to the
  2305. ** buffer at pFS->aOBuffer. The size of the compressed data is stored in
  2306. ** pPg->nCompress.
  2307. **
  2308. ** If buffer pFS->aOBuffer[] has not been allocated then this function
  2309. ** allocates it. If this fails, LSM_NOMEM is returned. Otherwise, LSM_OK.
  2310. */
  2311. static int fsCompressIntoBuffer(FileSystem *pFS, Page *pPg){
  2312. lsm_compress *p = pFS->pCompress;
  2313. if( fsAllocateBuffer(pFS, 1) ) return LSM_NOMEM;
  2314. assert( pPg->nData==pFS->nPagesize );
  2315. pPg->nCompress = pFS->nBuffer;
  2316. return p->xCompress(p->pCtx,
  2317. (char *)pFS->aOBuffer, &pPg->nCompress,
  2318. (const char *)pPg->aData, pPg->nData
  2319. );
  2320. }
  2321. /*
  2322. ** Append a new page to segment pSeg. Set output variable *piNew to the
  2323. ** page number of the new page before returning.
  2324. **
  2325. ** If the new page is the last on its block, then the 'next' block that
  2326. ** will be used by the segment is allocated here too. In this case output
  2327. ** variable *piNext is set to the block number of the next block.
  2328. **
  2329. ** If the new page is the first on its block but not the first in the
  2330. ** entire segment, set output variable *piPrev to the block number of
  2331. ** the previous block in the segment.
  2332. **
  2333. ** LSM_OK is returned if successful, or an lsm error code otherwise. If
  2334. ** any value other than LSM_OK is returned, then the final value of all
  2335. ** output variables is undefined.
  2336. */
  2337. static int fsAppendPage(
  2338. FileSystem *pFS,
  2339. Segment *pSeg,
  2340. LsmPgno *piNew,
  2341. int *piPrev,
  2342. int *piNext
  2343. ){
  2344. LsmPgno iPrev = pSeg->iLastPg;
  2345. int rc;
  2346. assert( iPrev!=0 );
  2347. *piPrev = 0;
  2348. *piNext = 0;
  2349. if( fsIsLast(pFS, iPrev) ){
  2350. /* Grab the first page on the next block (which has already be
  2351. ** allocated). In this case set *piPrev to tell the caller to set
  2352. ** the "previous block" pointer in the first 4 bytes of the page.
  2353. */
  2354. int iNext;
  2355. int iBlk = fsPageToBlock(pFS, iPrev);
  2356. assert( pSeg->pRedirect==0 );
  2357. rc = fsBlockNext(pFS, 0, iBlk, &iNext);
  2358. if( rc!=LSM_OK ) return rc;
  2359. *piNew = fsFirstPageOnBlock(pFS, iNext);
  2360. *piPrev = iBlk;
  2361. }else{
  2362. *piNew = iPrev+1;
  2363. if( fsIsLast(pFS, *piNew) ){
  2364. /* Allocate the next block here. */
  2365. int iBlk;
  2366. rc = lsmBlockAllocate(pFS->pDb, 0, &iBlk);
  2367. if( rc!=LSM_OK ) return rc;
  2368. *piNext = iBlk;
  2369. }
  2370. }
  2371. pSeg->nSize++;
  2372. pSeg->iLastPg = *piNew;
  2373. return LSM_OK;
  2374. }
  2375. /*
  2376. ** Flush all pages in the FileSystem.pWaiting list to disk.
  2377. */
  2378. void lsmFsFlushWaiting(FileSystem *pFS, int *pRc){
  2379. int rc = *pRc;
  2380. Page *pPg;
  2381. pPg = pFS->pWaiting;
  2382. pFS->pWaiting = 0;
  2383. while( pPg ){
  2384. Page *pNext = pPg->pWaitingNext;
  2385. if( rc==LSM_OK ) rc = lsmFsPagePersist(pPg);
  2386. assert( pPg->nRef==1 );
  2387. lsmFsPageRelease(pPg);
  2388. pPg = pNext;
  2389. }
  2390. *pRc = rc;
  2391. }
  2392. /*
  2393. ** If there exists a hash-table entry associated with page iPg, remove it.
  2394. */
  2395. static void fsRemoveHashEntry(FileSystem *pFS, LsmPgno iPg){
  2396. Page *p;
  2397. int iHash = fsHashKey(pFS->nHash, iPg);
  2398. for(p=pFS->apHash[iHash]; p && p->iPg!=iPg; p=p->pHashNext);
  2399. if( p ){
  2400. assert( p->nRef==0 || (p->flags & PAGE_FREE)==0 );
  2401. fsPageRemoveFromHash(pFS, p);
  2402. p->iPg = 0;
  2403. iHash = fsHashKey(pFS->nHash, 0);
  2404. p->pHashNext = pFS->apHash[iHash];
  2405. pFS->apHash[iHash] = p;
  2406. }
  2407. }
  2408. /*
  2409. ** If the page passed as an argument is dirty, update the database file
  2410. ** (or mapping of the database file) with its current contents and mark
  2411. ** the page as clean.
  2412. **
  2413. ** Return LSM_OK if the operation is a success, or an LSM error code
  2414. ** otherwise.
  2415. */
  2416. int lsmFsPagePersist(Page *pPg){
  2417. int rc = LSM_OK;
  2418. if( pPg && (pPg->flags & PAGE_DIRTY) ){
  2419. FileSystem *pFS = pPg->pFS;
  2420. if( pFS->pCompress ){
  2421. int iHash; /* Hash key of assigned page number */
  2422. u8 aSz[3]; /* pPg->nCompress as a 24-bit big-endian */
  2423. assert( pPg->pSeg && pPg->iPg==0 && pPg->nCompress==0 );
  2424. /* Compress the page image. */
  2425. rc = fsCompressIntoBuffer(pFS, pPg);
  2426. /* Serialize the compressed size into buffer aSz[] */
  2427. putRecordSize(aSz, pPg->nCompress, 0);
  2428. /* Write the serialized page record into the database file. */
  2429. pPg->iPg = fsAppendData(pFS, pPg->pSeg, aSz, sizeof(aSz), &rc);
  2430. fsAppendData(pFS, pPg->pSeg, pFS->aOBuffer, pPg->nCompress, &rc);
  2431. fsAppendData(pFS, pPg->pSeg, aSz, sizeof(aSz), &rc);
  2432. /* Now that it has a page number, insert the page into the hash table */
  2433. iHash = fsHashKey(pFS->nHash, pPg->iPg);
  2434. pPg->pHashNext = pFS->apHash[iHash];
  2435. pFS->apHash[iHash] = pPg;
  2436. pPg->pSeg->nSize += (sizeof(aSz) * 2) + pPg->nCompress;
  2437. pPg->flags &= ~PAGE_DIRTY;
  2438. pFS->nWrite++;
  2439. }else{
  2440. if( pPg->iPg==0 ){
  2441. /* No page number has been assigned yet. This occurs with pages used
  2442. ** in the b-tree hierarchy. They were not assigned page numbers when
  2443. ** they were created as doing so would cause this call to
  2444. ** lsmFsPagePersist() to write an out-of-order page. Instead a page
  2445. ** number is assigned here so that the page data will be appended
  2446. ** to the current segment.
  2447. */
  2448. Page **pp;
  2449. int iPrev = 0;
  2450. int iNext = 0;
  2451. int iHash;
  2452. assert( pPg->pSeg->iFirst );
  2453. assert( pPg->flags & PAGE_FREE );
  2454. assert( (pPg->flags & PAGE_HASPREV)==0 );
  2455. assert( pPg->nData==pFS->nPagesize-4 );
  2456. rc = fsAppendPage(pFS, pPg->pSeg, &pPg->iPg, &iPrev, &iNext);
  2457. if( rc!=LSM_OK ) return rc;
  2458. assert( pPg->flags & PAGE_FREE );
  2459. iHash = fsHashKey(pFS->nHash, pPg->iPg);
  2460. fsRemoveHashEntry(pFS, pPg->iPg);
  2461. pPg->pHashNext = pFS->apHash[iHash];
  2462. pFS->apHash[iHash] = pPg;
  2463. assert( pPg->pHashNext==0 || pPg->pHashNext->iPg!=pPg->iPg );
  2464. if( iPrev ){
  2465. assert( iNext==0 );
  2466. memmove(&pPg->aData[4], pPg->aData, pPg->nData);
  2467. lsmPutU32(pPg->aData, iPrev);
  2468. pPg->flags |= PAGE_HASPREV;
  2469. pPg->aData += 4;
  2470. }else if( iNext ){
  2471. assert( iPrev==0 );
  2472. lsmPutU32(&pPg->aData[pPg->nData], iNext);
  2473. }else{
  2474. int nData = pPg->nData;
  2475. pPg->nData += 4;
  2476. lsmSortedExpandBtreePage(pPg, nData);
  2477. }
  2478. pPg->nRef++;
  2479. for(pp=&pFS->pWaiting; *pp; pp=&(*pp)->pWaitingNext);
  2480. *pp = pPg;
  2481. assert( pPg->pWaitingNext==0 );
  2482. }else{
  2483. i64 iOff; /* Offset to write within database file */
  2484. iOff = (i64)pFS->nPagesize * (i64)(pPg->iPg-1);
  2485. if( fsMmapPage(pFS, pPg->iPg)==0 ){
  2486. u8 *aData = pPg->aData - (pPg->flags & PAGE_HASPREV);
  2487. rc = lsmEnvWrite(pFS->pEnv, pFS->fdDb, iOff, aData, pFS->nPagesize);
  2488. }else if( pPg->flags & PAGE_FREE ){
  2489. fsGrowMapping(pFS, iOff + pFS->nPagesize, &rc);
  2490. if( rc==LSM_OK ){
  2491. u8 *aTo = &((u8 *)(pFS->pMap))[iOff];
  2492. u8 *aFrom = pPg->aData - (pPg->flags & PAGE_HASPREV);
  2493. memcpy(aTo, aFrom, pFS->nPagesize);
  2494. lsmFree(pFS->pEnv, aFrom);
  2495. pFS->nCacheAlloc--;
  2496. pPg->aData = aTo + (pPg->flags & PAGE_HASPREV);
  2497. pPg->flags &= ~PAGE_FREE;
  2498. fsPageRemoveFromHash(pFS, pPg);
  2499. pPg->pMappedNext = pFS->pMapped;
  2500. pFS->pMapped = pPg;
  2501. }
  2502. }
  2503. lsmFsFlushWaiting(pFS, &rc);
  2504. pPg->flags &= ~PAGE_DIRTY;
  2505. pFS->nWrite++;
  2506. }
  2507. }
  2508. }
  2509. return rc;
  2510. }
  2511. /*
  2512. ** For non-compressed databases, this function is a no-op. For compressed
  2513. ** databases, it adds a padding record to the segment passed as the third
  2514. ** argument.
  2515. **
  2516. ** The size of the padding records is selected so that the last byte
  2517. ** written is the last byte of a disk sector. This means that if a
  2518. ** snapshot is taken and checkpointed, subsequent worker processes will
  2519. ** not write to any sector that contains checkpointed data.
  2520. */
  2521. int lsmFsSortedPadding(
  2522. FileSystem *pFS,
  2523. Snapshot *pSnapshot,
  2524. Segment *pSeg
  2525. ){
  2526. int rc = LSM_OK;
  2527. if( pFS->pCompress && pSeg->iFirst ){
  2528. LsmPgno iLast2;
  2529. LsmPgno iLast = pSeg->iLastPg; /* Current last page of segment */
  2530. int nPad; /* Bytes of padding required */
  2531. u8 aSz[3];
  2532. iLast2 = (1 + iLast/pFS->szSector) * pFS->szSector - 1;
  2533. assert( fsPageToBlock(pFS, iLast)==fsPageToBlock(pFS, iLast2) );
  2534. nPad = (int)(iLast2 - iLast);
  2535. if( iLast2>fsLastPageOnPagesBlock(pFS, iLast) ){
  2536. nPad -= 4;
  2537. }
  2538. assert( nPad>=0 );
  2539. if( nPad>=6 ){
  2540. pSeg->nSize += nPad;
  2541. nPad -= 6;
  2542. putRecordSize(aSz, nPad, 1);
  2543. fsAppendData(pFS, pSeg, aSz, sizeof(aSz), &rc);
  2544. memset(pFS->aOBuffer, 0, nPad);
  2545. fsAppendData(pFS, pSeg, pFS->aOBuffer, nPad, &rc);
  2546. fsAppendData(pFS, pSeg, aSz, sizeof(aSz), &rc);
  2547. }else if( nPad>0 ){
  2548. u8 aBuf[5] = {0,0,0,0,0};
  2549. aBuf[0] = (u8)nPad;
  2550. aBuf[nPad-1] = (u8)nPad;
  2551. fsAppendData(pFS, pSeg, aBuf, nPad, &rc);
  2552. }
  2553. assert( rc!=LSM_OK
  2554. || pSeg->iLastPg==fsLastPageOnPagesBlock(pFS, pSeg->iLastPg)
  2555. || ((pSeg->iLastPg + 1) % pFS->szSector)==0
  2556. );
  2557. }
  2558. return rc;
  2559. }
  2560. /*
  2561. ** Increment the reference count on the page object passed as the first
  2562. ** argument.
  2563. */
  2564. void lsmFsPageRef(Page *pPg){
  2565. if( pPg ){
  2566. pPg->nRef++;
  2567. }
  2568. }
  2569. /*
  2570. ** Release a page-reference obtained using fsPageGet().
  2571. */
  2572. int lsmFsPageRelease(Page *pPg){
  2573. int rc = LSM_OK;
  2574. if( pPg ){
  2575. assert( pPg->nRef>0 );
  2576. pPg->nRef--;
  2577. if( pPg->nRef==0 ){
  2578. FileSystem *pFS = pPg->pFS;
  2579. rc = lsmFsPagePersist(pPg);
  2580. pFS->nOut--;
  2581. assert( pPg->pFS->pCompress
  2582. || fsIsFirst(pPg->pFS, pPg->iPg)==0
  2583. || (pPg->flags & PAGE_HASPREV)
  2584. );
  2585. pPg->aData -= (pPg->flags & PAGE_HASPREV);
  2586. pPg->flags &= ~PAGE_HASPREV;
  2587. if( (pPg->flags & PAGE_FREE)==0 ){
  2588. /* Removed from mapped list */
  2589. Page **pp;
  2590. for(pp=&pFS->pMapped; (*pp)!=pPg; pp=&(*pp)->pMappedNext);
  2591. *pp = pPg->pMappedNext;
  2592. pPg->pMappedNext = 0;
  2593. /* Add to free list */
  2594. pPg->pFreeNext = pFS->pFree;
  2595. pFS->pFree = pPg;
  2596. }else{
  2597. fsPageAddToLru(pFS, pPg);
  2598. }
  2599. }
  2600. }
  2601. return rc;
  2602. }
  2603. /*
  2604. ** Return the total number of pages read from the database file.
  2605. */
  2606. int lsmFsNRead(FileSystem *pFS){ return pFS->nRead; }
  2607. /*
  2608. ** Return the total number of pages written to the database file.
  2609. */
  2610. int lsmFsNWrite(FileSystem *pFS){ return pFS->nWrite; }
  2611. /*
  2612. ** Return a copy of the environment pointer used by the file-system object.
  2613. */
  2614. lsm_env *lsmFsEnv(FileSystem *pFS){
  2615. return pFS->pEnv;
  2616. }
  2617. /*
  2618. ** Return a copy of the environment pointer used by the file-system object
  2619. ** to which this page belongs.
  2620. */
  2621. lsm_env *lsmPageEnv(Page *pPg) {
  2622. return pPg->pFS->pEnv;
  2623. }
  2624. /*
  2625. ** Return a pointer to the file-system object associated with the Page
  2626. ** passed as the only argument.
  2627. */
  2628. FileSystem *lsmPageFS(Page *pPg){
  2629. return pPg->pFS;
  2630. }
  2631. /*
  2632. ** Return the sector-size as reported by the log file handle.
  2633. */
  2634. int lsmFsSectorSize(FileSystem *pFS){
  2635. return pFS->szSector;
  2636. }
  2637. /*
  2638. ** Helper function for lsmInfoArrayStructure().
  2639. */
  2640. static Segment *startsWith(Segment *pRun, LsmPgno iFirst){
  2641. return (iFirst==pRun->iFirst) ? pRun : 0;
  2642. }
  2643. /*
  2644. ** Return the segment that starts with page iFirst, if any. If no such segment
  2645. ** can be found, return NULL.
  2646. */
  2647. static Segment *findSegment(Snapshot *pWorker, LsmPgno iFirst){
  2648. Level *pLvl; /* Used to iterate through db levels */
  2649. Segment *pSeg = 0; /* Pointer to segment to return */
  2650. for(pLvl=lsmDbSnapshotLevel(pWorker); pLvl && pSeg==0; pLvl=pLvl->pNext){
  2651. if( 0==(pSeg = startsWith(&pLvl->lhs, iFirst)) ){
  2652. int i;
  2653. for(i=0; i<pLvl->nRight; i++){
  2654. if( (pSeg = startsWith(&pLvl->aRhs[i], iFirst)) ) break;
  2655. }
  2656. }
  2657. }
  2658. return pSeg;
  2659. }
  2660. /*
  2661. ** This function implements the lsm_info(LSM_INFO_ARRAY_STRUCTURE) request.
  2662. ** If successful, *pzOut is set to point to a nul-terminated string
  2663. ** containing the array structure and LSM_OK is returned. The caller should
  2664. ** eventually free the string using lsmFree().
  2665. **
  2666. ** If an error occurs, *pzOut is set to NULL and an LSM error code returned.
  2667. */
  2668. int lsmInfoArrayStructure(
  2669. lsm_db *pDb,
  2670. int bBlock, /* True for block numbers only */
  2671. LsmPgno iFirst,
  2672. char **pzOut
  2673. ){
  2674. int rc = LSM_OK;
  2675. Snapshot *pWorker; /* Worker snapshot */
  2676. Segment *pArray = 0; /* Array to report on */
  2677. int bUnlock = 0;
  2678. *pzOut = 0;
  2679. if( iFirst==0 ) return LSM_ERROR;
  2680. /* Obtain the worker snapshot */
  2681. pWorker = pDb->pWorker;
  2682. if( !pWorker ){
  2683. rc = lsmBeginWork(pDb);
  2684. if( rc!=LSM_OK ) return rc;
  2685. pWorker = pDb->pWorker;
  2686. bUnlock = 1;
  2687. }
  2688. /* Search for the array that starts on page iFirst */
  2689. pArray = findSegment(pWorker, iFirst);
  2690. if( pArray==0 ){
  2691. /* Could not find the requested array. This is an error. */
  2692. rc = LSM_ERROR;
  2693. }else{
  2694. FileSystem *pFS = pDb->pFS;
  2695. LsmString str;
  2696. int iBlk;
  2697. int iLastBlk;
  2698. iBlk = fsPageToBlock(pFS, pArray->iFirst);
  2699. iLastBlk = fsPageToBlock(pFS, pArray->iLastPg);
  2700. lsmStringInit(&str, pDb->pEnv);
  2701. if( bBlock ){
  2702. lsmStringAppendf(&str, "%d", iBlk);
  2703. while( iBlk!=iLastBlk ){
  2704. fsBlockNext(pFS, pArray, iBlk, &iBlk);
  2705. lsmStringAppendf(&str, " %d", iBlk);
  2706. }
  2707. }else{
  2708. lsmStringAppendf(&str, "%d", pArray->iFirst);
  2709. while( iBlk!=iLastBlk ){
  2710. lsmStringAppendf(&str, " %d", fsLastPageOnBlock(pFS, iBlk));
  2711. fsBlockNext(pFS, pArray, iBlk, &iBlk);
  2712. lsmStringAppendf(&str, " %d", fsFirstPageOnBlock(pFS, iBlk));
  2713. }
  2714. lsmStringAppendf(&str, " %d", pArray->iLastPg);
  2715. }
  2716. *pzOut = str.z;
  2717. }
  2718. if( bUnlock ){
  2719. int rcwork = LSM_BUSY;
  2720. lsmFinishWork(pDb, 0, &rcwork);
  2721. }
  2722. return rc;
  2723. }
  2724. int lsmFsSegmentContainsPg(
  2725. FileSystem *pFS,
  2726. Segment *pSeg,
  2727. LsmPgno iPg,
  2728. int *pbRes
  2729. ){
  2730. Redirect *pRedir = pSeg->pRedirect;
  2731. int rc = LSM_OK;
  2732. int iBlk;
  2733. int iLastBlk;
  2734. int iPgBlock; /* Block containing page iPg */
  2735. iPgBlock = fsPageToBlock(pFS, pSeg->iFirst);
  2736. iBlk = fsRedirectBlock(pRedir, fsPageToBlock(pFS, pSeg->iFirst));
  2737. iLastBlk = fsRedirectBlock(pRedir, fsPageToBlock(pFS, pSeg->iLastPg));
  2738. while( iBlk!=iLastBlk && iBlk!=iPgBlock && rc==LSM_OK ){
  2739. rc = fsBlockNext(pFS, pSeg, iBlk, &iBlk);
  2740. }
  2741. *pbRes = (iBlk==iPgBlock);
  2742. return rc;
  2743. }
  2744. /*
  2745. ** This function implements the lsm_info(LSM_INFO_ARRAY_PAGES) request.
  2746. ** If successful, *pzOut is set to point to a nul-terminated string
  2747. ** containing the array structure and LSM_OK is returned. The caller should
  2748. ** eventually free the string using lsmFree().
  2749. **
  2750. ** If an error occurs, *pzOut is set to NULL and an LSM error code returned.
  2751. */
  2752. int lsmInfoArrayPages(lsm_db *pDb, LsmPgno iFirst, char **pzOut){
  2753. int rc = LSM_OK;
  2754. Snapshot *pWorker; /* Worker snapshot */
  2755. Segment *pSeg = 0; /* Array to report on */
  2756. int bUnlock = 0;
  2757. *pzOut = 0;
  2758. if( iFirst==0 ) return LSM_ERROR;
  2759. /* Obtain the worker snapshot */
  2760. pWorker = pDb->pWorker;
  2761. if( !pWorker ){
  2762. rc = lsmBeginWork(pDb);
  2763. if( rc!=LSM_OK ) return rc;
  2764. pWorker = pDb->pWorker;
  2765. bUnlock = 1;
  2766. }
  2767. /* Search for the array that starts on page iFirst */
  2768. pSeg = findSegment(pWorker, iFirst);
  2769. if( pSeg==0 ){
  2770. /* Could not find the requested array. This is an error. */
  2771. rc = LSM_ERROR;
  2772. }else{
  2773. Page *pPg = 0;
  2774. FileSystem *pFS = pDb->pFS;
  2775. LsmString str;
  2776. lsmStringInit(&str, pDb->pEnv);
  2777. rc = lsmFsDbPageGet(pFS, pSeg, iFirst, &pPg);
  2778. while( rc==LSM_OK && pPg ){
  2779. Page *pNext = 0;
  2780. lsmStringAppendf(&str, " %lld", lsmFsPageNumber(pPg));
  2781. rc = lsmFsDbPageNext(pSeg, pPg, 1, &pNext);
  2782. lsmFsPageRelease(pPg);
  2783. pPg = pNext;
  2784. }
  2785. if( rc!=LSM_OK ){
  2786. lsmFree(pDb->pEnv, str.z);
  2787. }else{
  2788. *pzOut = str.z;
  2789. }
  2790. }
  2791. if( bUnlock ){
  2792. int rcwork = LSM_BUSY;
  2793. lsmFinishWork(pDb, 0, &rcwork);
  2794. }
  2795. return rc;
  2796. }
  2797. /*
  2798. ** The following macros are used by the integrity-check code. Associated with
  2799. ** each block in the database is an 8-bit bit mask (the entry in the aUsed[]
  2800. ** array). As the integrity-check meanders through the database, it sets the
  2801. ** following bits to indicate how each block is used.
  2802. **
  2803. ** INTEGRITY_CHECK_FIRST_PG:
  2804. ** First page of block is in use by sorted run.
  2805. **
  2806. ** INTEGRITY_CHECK_LAST_PG:
  2807. ** Last page of block is in use by sorted run.
  2808. **
  2809. ** INTEGRITY_CHECK_USED:
  2810. ** At least one page of the block is in use by a sorted run.
  2811. **
  2812. ** INTEGRITY_CHECK_FREE:
  2813. ** The free block list contains an entry corresponding to this block.
  2814. */
  2815. #define INTEGRITY_CHECK_FIRST_PG 0x01
  2816. #define INTEGRITY_CHECK_LAST_PG 0x02
  2817. #define INTEGRITY_CHECK_USED 0x04
  2818. #define INTEGRITY_CHECK_FREE 0x08
  2819. /*
  2820. ** Helper function for lsmFsIntegrityCheck()
  2821. */
  2822. static void checkBlocks(
  2823. FileSystem *pFS,
  2824. Segment *pSeg,
  2825. int bExtra, /* If true, count the "next" block if any */
  2826. int nUsed,
  2827. u8 *aUsed
  2828. ){
  2829. if( pSeg ){
  2830. if( pSeg && pSeg->nSize>0 ){
  2831. int rc;
  2832. int iBlk; /* Current block (during iteration) */
  2833. int iLastBlk; /* Last block of segment */
  2834. int iFirstBlk; /* First block of segment */
  2835. int bLastIsLastOnBlock; /* True iLast is the last on its block */
  2836. assert( 0==fsSegmentRedirects(pFS, pSeg) );
  2837. iBlk = iFirstBlk = fsPageToBlock(pFS, pSeg->iFirst);
  2838. iLastBlk = fsPageToBlock(pFS, pSeg->iLastPg);
  2839. bLastIsLastOnBlock = (fsLastPageOnBlock(pFS, iLastBlk)==pSeg->iLastPg);
  2840. assert( iBlk>0 );
  2841. do {
  2842. /* iBlk is a part of this sorted run. */
  2843. aUsed[iBlk-1] |= INTEGRITY_CHECK_USED;
  2844. /* If the first page of this block is also part of the segment,
  2845. ** set the flag to indicate that the first page of iBlk is in use.
  2846. */
  2847. if( fsFirstPageOnBlock(pFS, iBlk)==pSeg->iFirst || iBlk!=iFirstBlk ){
  2848. assert( (aUsed[iBlk-1] & INTEGRITY_CHECK_FIRST_PG)==0 );
  2849. aUsed[iBlk-1] |= INTEGRITY_CHECK_FIRST_PG;
  2850. }
  2851. /* Unless the sorted run finishes before the last page on this block,
  2852. ** the last page of this block is also in use. */
  2853. if( iBlk!=iLastBlk || bLastIsLastOnBlock ){
  2854. assert( (aUsed[iBlk-1] & INTEGRITY_CHECK_LAST_PG)==0 );
  2855. aUsed[iBlk-1] |= INTEGRITY_CHECK_LAST_PG;
  2856. }
  2857. /* Special case. The sorted run being scanned is the output run of
  2858. ** a level currently undergoing an incremental merge. The sorted
  2859. ** run ends on the last page of iBlk, but the next block has already
  2860. ** been allocated. So mark it as in use as well. */
  2861. if( iBlk==iLastBlk && bLastIsLastOnBlock && bExtra ){
  2862. int iExtra = 0;
  2863. rc = fsBlockNext(pFS, pSeg, iBlk, &iExtra);
  2864. assert( rc==LSM_OK );
  2865. assert( aUsed[iExtra-1]==0 );
  2866. aUsed[iExtra-1] |= INTEGRITY_CHECK_USED;
  2867. aUsed[iExtra-1] |= INTEGRITY_CHECK_FIRST_PG;
  2868. aUsed[iExtra-1] |= INTEGRITY_CHECK_LAST_PG;
  2869. }
  2870. /* Move on to the next block in the sorted run. Or set iBlk to zero
  2871. ** in order to break out of the loop if this was the last block in
  2872. ** the run. */
  2873. if( iBlk==iLastBlk ){
  2874. iBlk = 0;
  2875. }else{
  2876. rc = fsBlockNext(pFS, pSeg, iBlk, &iBlk);
  2877. assert( rc==LSM_OK );
  2878. }
  2879. }while( iBlk );
  2880. }
  2881. }
  2882. }
  2883. typedef struct CheckFreelistCtx CheckFreelistCtx;
  2884. struct CheckFreelistCtx {
  2885. u8 *aUsed;
  2886. int nBlock;
  2887. };
  2888. static int checkFreelistCb(void *pCtx, int iBlk, i64 iSnapshot){
  2889. CheckFreelistCtx *p = (CheckFreelistCtx *)pCtx;
  2890. assert( iBlk>=1 );
  2891. assert( iBlk<=p->nBlock );
  2892. assert( p->aUsed[iBlk-1]==0 );
  2893. p->aUsed[iBlk-1] = INTEGRITY_CHECK_FREE;
  2894. return 0;
  2895. }
  2896. /*
  2897. ** This function checks that all blocks in the database file are accounted
  2898. ** for. For each block, exactly one of the following must be true:
  2899. **
  2900. ** + the block is part of a sorted run, or
  2901. ** + the block is on the free-block list
  2902. **
  2903. ** This function also checks that there are no references to blocks with
  2904. ** out-of-range block numbers.
  2905. **
  2906. ** If no errors are found, non-zero is returned. If an error is found, an
  2907. ** assert() fails.
  2908. */
  2909. int lsmFsIntegrityCheck(lsm_db *pDb){
  2910. CheckFreelistCtx ctx;
  2911. FileSystem *pFS = pDb->pFS;
  2912. int i;
  2913. int rc;
  2914. Freelist freelist = {0, 0, 0};
  2915. u8 *aUsed;
  2916. Level *pLevel;
  2917. Snapshot *pWorker = pDb->pWorker;
  2918. int nBlock = pWorker->nBlock;
  2919. #if 0
  2920. static int nCall = 0;
  2921. nCall++;
  2922. printf("%d calls\n", nCall);
  2923. #endif
  2924. aUsed = lsmMallocZero(pDb->pEnv, nBlock);
  2925. if( aUsed==0 ){
  2926. /* Malloc has failed. Since this function is only called within debug
  2927. ** builds, this probably means the user is running an OOM injection test.
  2928. ** Regardless, it will not be possible to run the integrity-check at this
  2929. ** time, so assume the database is Ok and return non-zero. */
  2930. return 1;
  2931. }
  2932. for(pLevel=pWorker->pLevel; pLevel; pLevel=pLevel->pNext){
  2933. int j;
  2934. checkBlocks(pFS, &pLevel->lhs, (pLevel->nRight!=0), nBlock, aUsed);
  2935. for(j=0; j<pLevel->nRight; j++){
  2936. checkBlocks(pFS, &pLevel->aRhs[j], 0, nBlock, aUsed);
  2937. }
  2938. }
  2939. /* Mark all blocks in the free-list as used */
  2940. ctx.aUsed = aUsed;
  2941. ctx.nBlock = nBlock;
  2942. rc = lsmWalkFreelist(pDb, 0, checkFreelistCb, (void *)&ctx);
  2943. if( rc==LSM_OK ){
  2944. for(i=0; i<nBlock; i++) assert( aUsed[i]!=0 );
  2945. }
  2946. lsmFree(pDb->pEnv, aUsed);
  2947. lsmFree(pDb->pEnv, freelist.aEntry);
  2948. return 1;
  2949. }
  2950. #ifndef NDEBUG
  2951. /*
  2952. ** Return true if pPg happens to be the last page in segment pSeg. Or false
  2953. ** otherwise. This function is only invoked as part of assert() conditions.
  2954. */
  2955. int lsmFsDbPageIsLast(Segment *pSeg, Page *pPg){
  2956. if( pPg->pFS->pCompress ){
  2957. LsmPgno iNext = 0;
  2958. int rc;
  2959. rc = fsNextPageOffset(pPg->pFS, pSeg, pPg->iPg, pPg->nCompress+6, &iNext);
  2960. return (rc!=LSM_OK || iNext==0);
  2961. }
  2962. return (pPg->iPg==pSeg->iLastPg);
  2963. }
  2964. #endif