xfs-delayed-logging-design.rst 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. .. SPDX-License-Identifier: GPL-2.0
  2. ==================
  3. XFS Logging Design
  4. ==================
  5. Preamble
  6. ========
  7. This document describes the design and algorithms that the XFS journalling
  8. subsystem is based on. This document describes the design and algorithms that
  9. the XFS journalling subsystem is based on so that readers may familiarize
  10. themselves with the general concepts of how transaction processing in XFS works.
  11. We begin with an overview of transactions in XFS, followed by describing how
  12. transaction reservations are structured and accounted, and then move into how we
  13. guarantee forwards progress for long running transactions with finite initial
  14. reservations bounds. At this point we need to explain how relogging works. With
  15. the basic concepts covered, the design of the delayed logging mechanism is
  16. documented.
  17. Introduction
  18. ============
  19. XFS uses Write Ahead Logging for ensuring changes to the filesystem metadata
  20. are atomic and recoverable. For reasons of space and time efficiency, the
  21. logging mechanisms are varied and complex, combining intents, logical and
  22. physical logging mechanisms to provide the necessary recovery guarantees the
  23. filesystem requires.
  24. Some objects, such as inodes and dquots, are logged in logical format where the
  25. details logged are made up of the changes to in-core structures rather than
  26. on-disk structures. Other objects - typically buffers - have their physical
  27. changes logged. Long running atomic modifications have individual changes
  28. chained together by intents, ensuring that journal recovery can restart and
  29. finish an operation that was only partially done when the system stopped
  30. functioning.
  31. The reason for these differences is to keep the amount of log space and CPU time
  32. required to process objects being modified as small as possible and hence the
  33. logging overhead as low as possible. Some items are very frequently modified,
  34. and some parts of objects are more frequently modified than others, so keeping
  35. the overhead of metadata logging low is of prime importance.
  36. The method used to log an item or chain modifications together isn't
  37. particularly important in the scope of this document. It suffices to know that
  38. the method used for logging a particular object or chaining modifications
  39. together are different and are dependent on the object and/or modification being
  40. performed. The logging subsystem only cares that certain specific rules are
  41. followed to guarantee forwards progress and prevent deadlocks.
  42. Transactions in XFS
  43. ===================
  44. XFS has two types of high level transactions, defined by the type of log space
  45. reservation they take. These are known as "one shot" and "permanent"
  46. transactions. Permanent transaction reservations can take reservations that span
  47. commit boundaries, whilst "one shot" transactions are for a single atomic
  48. modification.
  49. The type and size of reservation must be matched to the modification taking
  50. place. This means that permanent transactions can be used for one-shot
  51. modifications, but one-shot reservations cannot be used for permanent
  52. transactions.
  53. In the code, a one-shot transaction pattern looks somewhat like this::
  54. tp = xfs_trans_alloc(<reservation>)
  55. <lock items>
  56. <join item to transaction>
  57. <do modification>
  58. xfs_trans_commit(tp);
  59. As items are modified in the transaction, the dirty regions in those items are
  60. tracked via the transaction handle. Once the transaction is committed, all
  61. resources joined to it are released, along with the remaining unused reservation
  62. space that was taken at the transaction allocation time.
  63. In contrast, a permanent transaction is made up of multiple linked individual
  64. transactions, and the pattern looks like this::
  65. tp = xfs_trans_alloc(<reservation>)
  66. xfs_ilock(ip, XFS_ILOCK_EXCL)
  67. loop {
  68. xfs_trans_ijoin(tp, 0);
  69. <do modification>
  70. xfs_trans_log_inode(tp, ip);
  71. xfs_trans_roll(&tp);
  72. }
  73. xfs_trans_commit(tp);
  74. xfs_iunlock(ip, XFS_ILOCK_EXCL);
  75. While this might look similar to a one-shot transaction, there is an important
  76. difference: xfs_trans_roll() performs a specific operation that links two
  77. transactions together::
  78. ntp = xfs_trans_dup(tp);
  79. xfs_trans_commit(tp);
  80. xfs_trans_reserve(ntp);
  81. This results in a series of "rolling transactions" where the inode is locked
  82. across the entire chain of transactions. Hence while this series of rolling
  83. transactions is running, nothing else can read from or write to the inode and
  84. this provides a mechanism for complex changes to appear atomic from an external
  85. observer's point of view.
  86. It is important to note that a series of rolling transactions in a permanent
  87. transaction does not form an atomic change in the journal. While each
  88. individual modification is atomic, the chain is *not atomic*. If we crash half
  89. way through, then recovery will only replay up to the last transactional
  90. modification the loop made that was committed to the journal.
  91. This affects long running permanent transactions in that it is not possible to
  92. predict how much of a long running operation will actually be recovered because
  93. there is no guarantee of how much of the operation reached stale storage. Hence
  94. if a long running operation requires multiple transactions to fully complete,
  95. the high level operation must use intents and deferred operations to guarantee
  96. recovery can complete the operation once the first transactions is persisted in
  97. the on-disk journal.
  98. Transactions are Asynchronous
  99. =============================
  100. In XFS, all high level transactions are asynchronous by default. This means that
  101. xfs_trans_commit() does not guarantee that the modification has been committed
  102. to stable storage when it returns. Hence when a system crashes, not all the
  103. completed transactions will be replayed during recovery.
  104. However, the logging subsystem does provide global ordering guarantees, such
  105. that if a specific change is seen after recovery, all metadata modifications
  106. that were committed prior to that change will also be seen.
  107. For single shot operations that need to reach stable storage immediately, or
  108. ensuring that a long running permanent transaction is fully committed once it is
  109. complete, we can explicitly tag a transaction as synchronous. This will trigger
  110. a "log force" to flush the outstanding committed transactions to stable storage
  111. in the journal and wait for that to complete.
  112. Synchronous transactions are rarely used, however, because they limit logging
  113. throughput to the IO latency limitations of the underlying storage. Instead, we
  114. tend to use log forces to ensure modifications are on stable storage only when
  115. a user operation requires a synchronisation point to occur (e.g. fsync).
  116. Transaction Reservations
  117. ========================
  118. It has been mentioned a number of times now that the logging subsystem needs to
  119. provide a forwards progress guarantee so that no modification ever stalls
  120. because it can't be written to the journal due to a lack of space in the
  121. journal. This is achieved by the transaction reservations that are made when
  122. a transaction is first allocated. For permanent transactions, these reservations
  123. are maintained as part of the transaction rolling mechanism.
  124. A transaction reservation provides a guarantee that there is physical log space
  125. available to write the modification into the journal before we start making
  126. modifications to objects and items. As such, the reservation needs to be large
  127. enough to take into account the amount of metadata that the change might need to
  128. log in the worst case. This means that if we are modifying a btree in the
  129. transaction, we have to reserve enough space to record a full leaf-to-root split
  130. of the btree. As such, the reservations are quite complex because we have to
  131. take into account all the hidden changes that might occur.
  132. For example, a user data extent allocation involves allocating an extent from
  133. free space, which modifies the free space trees. That's two btrees. Inserting
  134. the extent into the inode's extent map might require a split of the extent map
  135. btree, which requires another allocation that can modify the free space trees
  136. again. Then we might have to update reverse mappings, which modifies yet
  137. another btree which might require more space. And so on. Hence the amount of
  138. metadata that a "simple" operation can modify can be quite large.
  139. This "worst case" calculation provides us with the static "unit reservation"
  140. for the transaction that is calculated at mount time. We must guarantee that the
  141. log has this much space available before the transaction is allowed to proceed
  142. so that when we come to write the dirty metadata into the log we don't run out
  143. of log space half way through the write.
  144. For one-shot transactions, a single unit space reservation is all that is
  145. required for the transaction to proceed. For permanent transactions, however, we
  146. also have a "log count" that affects the size of the reservation that is to be
  147. made.
  148. While a permanent transaction can get by with a single unit of space
  149. reservation, it is somewhat inefficient to do this as it requires the
  150. transaction rolling mechanism to re-reserve space on every transaction roll. We
  151. know from the implementation of the permanent transactions how many transaction
  152. rolls are likely for the common modifications that need to be made.
  153. For example, an inode allocation is typically two transactions - one to
  154. physically allocate a free inode chunk on disk, and another to allocate an inode
  155. from an inode chunk that has free inodes in it. Hence for an inode allocation
  156. transaction, we might set the reservation log count to a value of 2 to indicate
  157. that the common/fast path transaction will commit two linked transactions in a
  158. chain. Each time a permanent transaction rolls, it consumes an entire unit
  159. reservation.
  160. Hence when the permanent transaction is first allocated, the log space
  161. reservation is increased from a single unit reservation to multiple unit
  162. reservations. That multiple is defined by the reservation log count, and this
  163. means we can roll the transaction multiple times before we have to re-reserve
  164. log space when we roll the transaction. This ensures that the common
  165. modifications we make only need to reserve log space once.
  166. If the log count for a permanent transaction reaches zero, then it needs to
  167. re-reserve physical space in the log. This is somewhat complex, and requires
  168. an understanding of how the log accounts for space that has been reserved.
  169. Log Space Accounting
  170. ====================
  171. The position in the log is typically referred to as a Log Sequence Number (LSN).
  172. The log is circular, so the positions in the log are defined by the combination
  173. of a cycle number - the number of times the log has been overwritten - and the
  174. offset into the log. A LSN carries the cycle in the upper 32 bits and the
  175. offset in the lower 32 bits. The offset is in units of "basic blocks" (512
  176. bytes). Hence we can do realtively simple LSN based math to keep track of
  177. available space in the log.
  178. Log space accounting is done via a pair of constructs called "grant heads". The
  179. position of the grant heads is an absolute value, so the amount of space
  180. available in the log is defined by the distance between the position of the
  181. grant head and the current log tail. That is, how much space can be
  182. reserved/consumed before the grant heads would fully wrap the log and overtake
  183. the tail position.
  184. The first grant head is the "reserve" head. This tracks the byte count of the
  185. reservations currently held by active transactions. It is a purely in-memory
  186. accounting of the space reservation and, as such, actually tracks byte offsets
  187. into the log rather than basic blocks. Hence it technically isn't using LSNs to
  188. represent the log position, but it is still treated like a split {cycle,offset}
  189. tuple for the purposes of tracking reservation space.
  190. The reserve grant head is used to accurately account for exact transaction
  191. reservations amounts and the exact byte count that modifications actually make
  192. and need to write into the log. The reserve head is used to prevent new
  193. transactions from taking new reservations when the head reaches the current
  194. tail. It will block new reservations in a FIFO queue and as the log tail moves
  195. forward it will wake them in order once sufficient space is available. This FIFO
  196. mechanism ensures no transaction is starved of resources when log space
  197. shortages occur.
  198. The other grant head is the "write" head. Unlike the reserve head, this grant
  199. head contains an LSN and it tracks the physical space usage in the log. While
  200. this might sound like it is accounting the same state as the reserve grant head
  201. - and it mostly does track exactly the same location as the reserve grant head -
  202. there are critical differences in behaviour between them that provides the
  203. forwards progress guarantees that rolling permanent transactions require.
  204. These differences when a permanent transaction is rolled and the internal "log
  205. count" reaches zero and the initial set of unit reservations have been
  206. exhausted. At this point, we still require a log space reservation to continue
  207. the next transaction in the sequeunce, but we have none remaining. We cannot
  208. sleep during the transaction commit process waiting for new log space to become
  209. available, as we may end up on the end of the FIFO queue and the items we have
  210. locked while we sleep could end up pinning the tail of the log before there is
  211. enough free space in the log to fulfill all of the pending reservations and
  212. then wake up transaction commit in progress.
  213. To take a new reservation without sleeping requires us to be able to take a
  214. reservation even if there is no reservation space currently available. That is,
  215. we need to be able to *overcommit* the log reservation space. As has already
  216. been detailed, we cannot overcommit physical log space. However, the reserve
  217. grant head does not track physical space - it only accounts for the amount of
  218. reservations we currently have outstanding. Hence if the reserve head passes
  219. over the tail of the log all it means is that new reservations will be throttled
  220. immediately and remain throttled until the log tail is moved forward far enough
  221. to remove the overcommit and start taking new reservations. In other words, we
  222. can overcommit the reserve head without violating the physical log head and tail
  223. rules.
  224. As a result, permanent transactions only "regrant" reservation space during
  225. xfs_trans_commit() calls, while the physical log space reservation - tracked by
  226. the write head - is then reserved separately by a call to xfs_log_reserve()
  227. after the commit completes. Once the commit completes, we can sleep waiting for
  228. physical log space to be reserved from the write grant head, but only if one
  229. critical rule has been observed::
  230. Code using permanent reservations must always log the items they hold
  231. locked across each transaction they roll in the chain.
  232. "Re-logging" the locked items on every transaction roll ensures that the items
  233. attached to the transaction chain being rolled are always relocated to the
  234. physical head of the log and so do not pin the tail of the log. If a locked item
  235. pins the tail of the log when we sleep on the write reservation, then we will
  236. deadlock the log as we cannot take the locks needed to write back that item and
  237. move the tail of the log forwards to free up write grant space. Re-logging the
  238. locked items avoids this deadlock and guarantees that the log reservation we are
  239. making cannot self-deadlock.
  240. If all rolling transactions obey this rule, then they can all make forwards
  241. progress independently because nothing will block the progress of the log
  242. tail moving forwards and hence ensuring that write grant space is always
  243. (eventually) made available to permanent transactions no matter how many times
  244. they roll.
  245. Re-logging Explained
  246. ====================
  247. XFS allows multiple separate modifications to a single object to be carried in
  248. the log at any given time. This allows the log to avoid needing to flush each
  249. change to disk before recording a new change to the object. XFS does this via a
  250. method called "re-logging". Conceptually, this is quite simple - all it requires
  251. is that any new change to the object is recorded with a *new copy* of all the
  252. existing changes in the new transaction that is written to the log.
  253. That is, if we have a sequence of changes A through to F, and the object was
  254. written to disk after change D, we would see in the log the following series
  255. of transactions, their contents and the log sequence number (LSN) of the
  256. transaction::
  257. Transaction Contents LSN
  258. A A X
  259. B A+B X+n
  260. C A+B+C X+n+m
  261. D A+B+C+D X+n+m+o
  262. <object written to disk>
  263. E E Y (> X+n+m+o)
  264. F E+F Y+p
  265. In other words, each time an object is relogged, the new transaction contains
  266. the aggregation of all the previous changes currently held only in the log.
  267. This relogging technique allows objects to be moved forward in the log so that
  268. an object being relogged does not prevent the tail of the log from ever moving
  269. forward. This can be seen in the table above by the changing (increasing) LSN
  270. of each subsequent transaction, and it's the technique that allows us to
  271. implement long-running, multiple-commit permanent transactions.
  272. A typical example of a rolling transaction is the removal of extents from an
  273. inode which can only be done at a rate of two extents per transaction because
  274. of reservation size limitations. Hence a rolling extent removal transaction
  275. keeps relogging the inode and btree buffers as they get modified in each
  276. removal operation. This keeps them moving forward in the log as the operation
  277. progresses, ensuring that current operation never gets blocked by itself if the
  278. log wraps around.
  279. Hence it can be seen that the relogging operation is fundamental to the correct
  280. working of the XFS journalling subsystem. From the above description, most
  281. people should be able to see why the XFS metadata operations writes so much to
  282. the log - repeated operations to the same objects write the same changes to
  283. the log over and over again. Worse is the fact that objects tend to get
  284. dirtier as they get relogged, so each subsequent transaction is writing more
  285. metadata into the log.
  286. It should now also be obvious how relogging and asynchronous transactions go
  287. hand in hand. That is, transactions don't get written to the physical journal
  288. until either a log buffer is filled (a log buffer can hold multiple
  289. transactions) or a synchronous operation forces the log buffers holding the
  290. transactions to disk. This means that XFS is doing aggregation of transactions
  291. in memory - batching them, if you like - to minimise the impact of the log IO on
  292. transaction throughput.
  293. The limitation on asynchronous transaction throughput is the number and size of
  294. log buffers made available by the log manager. By default there are 8 log
  295. buffers available and the size of each is 32kB - the size can be increased up
  296. to 256kB by use of a mount option.
  297. Effectively, this gives us the maximum bound of outstanding metadata changes
  298. that can be made to the filesystem at any point in time - if all the log
  299. buffers are full and under IO, then no more transactions can be committed until
  300. the current batch completes. It is now common for a single current CPU core to
  301. be to able to issue enough transactions to keep the log buffers full and under
  302. IO permanently. Hence the XFS journalling subsystem can be considered to be IO
  303. bound.
  304. Delayed Logging: Concepts
  305. =========================
  306. The key thing to note about the asynchronous logging combined with the
  307. relogging technique XFS uses is that we can be relogging changed objects
  308. multiple times before they are committed to disk in the log buffers. If we
  309. return to the previous relogging example, it is entirely possible that
  310. transactions A through D are committed to disk in the same log buffer.
  311. That is, a single log buffer may contain multiple copies of the same object,
  312. but only one of those copies needs to be there - the last one "D", as it
  313. contains all the changes from the previous changes. In other words, we have one
  314. necessary copy in the log buffer, and three stale copies that are simply
  315. wasting space. When we are doing repeated operations on the same set of
  316. objects, these "stale objects" can be over 90% of the space used in the log
  317. buffers. It is clear that reducing the number of stale objects written to the
  318. log would greatly reduce the amount of metadata we write to the log, and this
  319. is the fundamental goal of delayed logging.
  320. From a conceptual point of view, XFS is already doing relogging in memory (where
  321. memory == log buffer), only it is doing it extremely inefficiently. It is using
  322. logical to physical formatting to do the relogging because there is no
  323. infrastructure to keep track of logical changes in memory prior to physically
  324. formatting the changes in a transaction to the log buffer. Hence we cannot avoid
  325. accumulating stale objects in the log buffers.
  326. Delayed logging is the name we've given to keeping and tracking transactional
  327. changes to objects in memory outside the log buffer infrastructure. Because of
  328. the relogging concept fundamental to the XFS journalling subsystem, this is
  329. actually relatively easy to do - all the changes to logged items are already
  330. tracked in the current infrastructure. The big problem is how to accumulate
  331. them and get them to the log in a consistent, recoverable manner.
  332. Describing the problems and how they have been solved is the focus of this
  333. document.
  334. One of the key changes that delayed logging makes to the operation of the
  335. journalling subsystem is that it disassociates the amount of outstanding
  336. metadata changes from the size and number of log buffers available. In other
  337. words, instead of there only being a maximum of 2MB of transaction changes not
  338. written to the log at any point in time, there may be a much greater amount
  339. being accumulated in memory. Hence the potential for loss of metadata on a
  340. crash is much greater than for the existing logging mechanism.
  341. It should be noted that this does not change the guarantee that log recovery
  342. will result in a consistent filesystem. What it does mean is that as far as the
  343. recovered filesystem is concerned, there may be many thousands of transactions
  344. that simply did not occur as a result of the crash. This makes it even more
  345. important that applications that care about their data use fsync() where they
  346. need to ensure application level data integrity is maintained.
  347. It should be noted that delayed logging is not an innovative new concept that
  348. warrants rigorous proofs to determine whether it is correct or not. The method
  349. of accumulating changes in memory for some period before writing them to the
  350. log is used effectively in many filesystems including ext3 and ext4. Hence
  351. no time is spent in this document trying to convince the reader that the
  352. concept is sound. Instead it is simply considered a "solved problem" and as
  353. such implementing it in XFS is purely an exercise in software engineering.
  354. The fundamental requirements for delayed logging in XFS are simple:
  355. 1. Reduce the amount of metadata written to the log by at least
  356. an order of magnitude.
  357. 2. Supply sufficient statistics to validate Requirement #1.
  358. 3. Supply sufficient new tracing infrastructure to be able to debug
  359. problems with the new code.
  360. 4. No on-disk format change (metadata or log format).
  361. 5. Enable and disable with a mount option.
  362. 6. No performance regressions for synchronous transaction workloads.
  363. Delayed Logging: Design
  364. =======================
  365. Storing Changes
  366. ---------------
  367. The problem with accumulating changes at a logical level (i.e. just using the
  368. existing log item dirty region tracking) is that when it comes to writing the
  369. changes to the log buffers, we need to ensure that the object we are formatting
  370. is not changing while we do this. This requires locking the object to prevent
  371. concurrent modification. Hence flushing the logical changes to the log would
  372. require us to lock every object, format them, and then unlock them again.
  373. This introduces lots of scope for deadlocks with transactions that are already
  374. running. For example, a transaction has object A locked and modified, but needs
  375. the delayed logging tracking lock to commit the transaction. However, the
  376. flushing thread has the delayed logging tracking lock already held, and is
  377. trying to get the lock on object A to flush it to the log buffer. This appears
  378. to be an unsolvable deadlock condition, and it was solving this problem that
  379. was the barrier to implementing delayed logging for so long.
  380. The solution is relatively simple - it just took a long time to recognise it.
  381. Put simply, the current logging code formats the changes to each item into an
  382. vector array that points to the changed regions in the item. The log write code
  383. simply copies the memory these vectors point to into the log buffer during
  384. transaction commit while the item is locked in the transaction. Instead of
  385. using the log buffer as the destination of the formatting code, we can use an
  386. allocated memory buffer big enough to fit the formatted vector.
  387. If we then copy the vector into the memory buffer and rewrite the vector to
  388. point to the memory buffer rather than the object itself, we now have a copy of
  389. the changes in a format that is compatible with the log buffer writing code.
  390. that does not require us to lock the item to access. This formatting and
  391. rewriting can all be done while the object is locked during transaction commit,
  392. resulting in a vector that is transactionally consistent and can be accessed
  393. without needing to lock the owning item.
  394. Hence we avoid the need to lock items when we need to flush outstanding
  395. asynchronous transactions to the log. The differences between the existing
  396. formatting method and the delayed logging formatting can be seen in the
  397. diagram below.
  398. Current format log vector::
  399. Object +---------------------------------------------+
  400. Vector 1 +----+
  401. Vector 2 +----+
  402. Vector 3 +----------+
  403. After formatting::
  404. Log Buffer +-V1-+-V2-+----V3----+
  405. Delayed logging vector::
  406. Object +---------------------------------------------+
  407. Vector 1 +----+
  408. Vector 2 +----+
  409. Vector 3 +----------+
  410. After formatting::
  411. Memory Buffer +-V1-+-V2-+----V3----+
  412. Vector 1 +----+
  413. Vector 2 +----+
  414. Vector 3 +----------+
  415. The memory buffer and associated vector need to be passed as a single object,
  416. but still need to be associated with the parent object so if the object is
  417. relogged we can replace the current memory buffer with a new memory buffer that
  418. contains the latest changes.
  419. The reason for keeping the vector around after we've formatted the memory
  420. buffer is to support splitting vectors across log buffer boundaries correctly.
  421. If we don't keep the vector around, we do not know where the region boundaries
  422. are in the item, so we'd need a new encapsulation method for regions in the log
  423. buffer writing (i.e. double encapsulation). This would be an on-disk format
  424. change and as such is not desirable. It also means we'd have to write the log
  425. region headers in the formatting stage, which is problematic as there is per
  426. region state that needs to be placed into the headers during the log write.
  427. Hence we need to keep the vector, but by attaching the memory buffer to it and
  428. rewriting the vector addresses to point at the memory buffer we end up with a
  429. self-describing object that can be passed to the log buffer write code to be
  430. handled in exactly the same manner as the existing log vectors are handled.
  431. Hence we avoid needing a new on-disk format to handle items that have been
  432. relogged in memory.
  433. Tracking Changes
  434. ----------------
  435. Now that we can record transactional changes in memory in a form that allows
  436. them to be used without limitations, we need to be able to track and accumulate
  437. them so that they can be written to the log at some later point in time. The
  438. log item is the natural place to store this vector and buffer, and also makes sense
  439. to be the object that is used to track committed objects as it will always
  440. exist once the object has been included in a transaction.
  441. The log item is already used to track the log items that have been written to
  442. the log but not yet written to disk. Such log items are considered "active"
  443. and as such are stored in the Active Item List (AIL) which is a LSN-ordered
  444. double linked list. Items are inserted into this list during log buffer IO
  445. completion, after which they are unpinned and can be written to disk. An object
  446. that is in the AIL can be relogged, which causes the object to be pinned again
  447. and then moved forward in the AIL when the log buffer IO completes for that
  448. transaction.
  449. Essentially, this shows that an item that is in the AIL can still be modified
  450. and relogged, so any tracking must be separate to the AIL infrastructure. As
  451. such, we cannot reuse the AIL list pointers for tracking committed items, nor
  452. can we store state in any field that is protected by the AIL lock. Hence the
  453. committed item tracking needs its own locks, lists and state fields in the log
  454. item.
  455. Similar to the AIL, tracking of committed items is done through a new list
  456. called the Committed Item List (CIL). The list tracks log items that have been
  457. committed and have formatted memory buffers attached to them. It tracks objects
  458. in transaction commit order, so when an object is relogged it is removed from
  459. its place in the list and re-inserted at the tail. This is entirely arbitrary
  460. and done to make it easy for debugging - the last items in the list are the
  461. ones that are most recently modified. Ordering of the CIL is not necessary for
  462. transactional integrity (as discussed in the next section) so the ordering is
  463. done for convenience/sanity of the developers.
  464. Delayed Logging: Checkpoints
  465. ----------------------------
  466. When we have a log synchronisation event, commonly known as a "log force",
  467. all the items in the CIL must be written into the log via the log buffers.
  468. We need to write these items in the order that they exist in the CIL, and they
  469. need to be written as an atomic transaction. The need for all the objects to be
  470. written as an atomic transaction comes from the requirements of relogging and
  471. log replay - all the changes in all the objects in a given transaction must
  472. either be completely replayed during log recovery, or not replayed at all. If
  473. a transaction is not replayed because it is not complete in the log, then
  474. no later transactions should be replayed, either.
  475. To fulfill this requirement, we need to write the entire CIL in a single log
  476. transaction. Fortunately, the XFS log code has no fixed limit on the size of a
  477. transaction, nor does the log replay code. The only fundamental limit is that
  478. the transaction cannot be larger than just under half the size of the log. The
  479. reason for this limit is that to find the head and tail of the log, there must
  480. be at least one complete transaction in the log at any given time. If a
  481. transaction is larger than half the log, then there is the possibility that a
  482. crash during the write of a such a transaction could partially overwrite the
  483. only complete previous transaction in the log. This will result in a recovery
  484. failure and an inconsistent filesystem and hence we must enforce the maximum
  485. size of a checkpoint to be slightly less than a half the log.
  486. Apart from this size requirement, a checkpoint transaction looks no different
  487. to any other transaction - it contains a transaction header, a series of
  488. formatted log items and a commit record at the tail. From a recovery
  489. perspective, the checkpoint transaction is also no different - just a lot
  490. bigger with a lot more items in it. The worst case effect of this is that we
  491. might need to tune the recovery transaction object hash size.
  492. Because the checkpoint is just another transaction and all the changes to log
  493. items are stored as log vectors, we can use the existing log buffer writing
  494. code to write the changes into the log. To do this efficiently, we need to
  495. minimise the time we hold the CIL locked while writing the checkpoint
  496. transaction. The current log write code enables us to do this easily with the
  497. way it separates the writing of the transaction contents (the log vectors) from
  498. the transaction commit record, but tracking this requires us to have a
  499. per-checkpoint context that travels through the log write process through to
  500. checkpoint completion.
  501. Hence a checkpoint has a context that tracks the state of the current
  502. checkpoint from initiation to checkpoint completion. A new context is initiated
  503. at the same time a checkpoint transaction is started. That is, when we remove
  504. all the current items from the CIL during a checkpoint operation, we move all
  505. those changes into the current checkpoint context. We then initialise a new
  506. context and attach that to the CIL for aggregation of new transactions.
  507. This allows us to unlock the CIL immediately after transfer of all the
  508. committed items and effectively allows new transactions to be issued while we
  509. are formatting the checkpoint into the log. It also allows concurrent
  510. checkpoints to be written into the log buffers in the case of log force heavy
  511. workloads, just like the existing transaction commit code does. This, however,
  512. requires that we strictly order the commit records in the log so that
  513. checkpoint sequence order is maintained during log replay.
  514. To ensure that we can be writing an item into a checkpoint transaction at
  515. the same time another transaction modifies the item and inserts the log item
  516. into the new CIL, then checkpoint transaction commit code cannot use log items
  517. to store the list of log vectors that need to be written into the transaction.
  518. Hence log vectors need to be able to be chained together to allow them to be
  519. detached from the log items. That is, when the CIL is flushed the memory
  520. buffer and log vector attached to each log item needs to be attached to the
  521. checkpoint context so that the log item can be released. In diagrammatic form,
  522. the CIL would look like this before the flush::
  523. CIL Head
  524. |
  525. V
  526. Log Item <-> log vector 1 -> memory buffer
  527. | -> vector array
  528. V
  529. Log Item <-> log vector 2 -> memory buffer
  530. | -> vector array
  531. V
  532. ......
  533. |
  534. V
  535. Log Item <-> log vector N-1 -> memory buffer
  536. | -> vector array
  537. V
  538. Log Item <-> log vector N -> memory buffer
  539. -> vector array
  540. And after the flush the CIL head is empty, and the checkpoint context log
  541. vector list would look like::
  542. Checkpoint Context
  543. |
  544. V
  545. log vector 1 -> memory buffer
  546. | -> vector array
  547. | -> Log Item
  548. V
  549. log vector 2 -> memory buffer
  550. | -> vector array
  551. | -> Log Item
  552. V
  553. ......
  554. |
  555. V
  556. log vector N-1 -> memory buffer
  557. | -> vector array
  558. | -> Log Item
  559. V
  560. log vector N -> memory buffer
  561. -> vector array
  562. -> Log Item
  563. Once this transfer is done, the CIL can be unlocked and new transactions can
  564. start, while the checkpoint flush code works over the log vector chain to
  565. commit the checkpoint.
  566. Once the checkpoint is written into the log buffers, the checkpoint context is
  567. attached to the log buffer that the commit record was written to along with a
  568. completion callback. Log IO completion will call that callback, which can then
  569. run transaction committed processing for the log items (i.e. insert into AIL
  570. and unpin) in the log vector chain and then free the log vector chain and
  571. checkpoint context.
  572. Discussion Point: I am uncertain as to whether the log item is the most
  573. efficient way to track vectors, even though it seems like the natural way to do
  574. it. The fact that we walk the log items (in the CIL) just to chain the log
  575. vectors and break the link between the log item and the log vector means that
  576. we take a cache line hit for the log item list modification, then another for
  577. the log vector chaining. If we track by the log vectors, then we only need to
  578. break the link between the log item and the log vector, which means we should
  579. dirty only the log item cachelines. Normally I wouldn't be concerned about one
  580. vs two dirty cachelines except for the fact I've seen upwards of 80,000 log
  581. vectors in one checkpoint transaction. I'd guess this is a "measure and
  582. compare" situation that can be done after a working and reviewed implementation
  583. is in the dev tree....
  584. Delayed Logging: Checkpoint Sequencing
  585. --------------------------------------
  586. One of the key aspects of the XFS transaction subsystem is that it tags
  587. committed transactions with the log sequence number of the transaction commit.
  588. This allows transactions to be issued asynchronously even though there may be
  589. future operations that cannot be completed until that transaction is fully
  590. committed to the log. In the rare case that a dependent operation occurs (e.g.
  591. re-using a freed metadata extent for a data extent), a special, optimised log
  592. force can be issued to force the dependent transaction to disk immediately.
  593. To do this, transactions need to record the LSN of the commit record of the
  594. transaction. This LSN comes directly from the log buffer the transaction is
  595. written into. While this works just fine for the existing transaction
  596. mechanism, it does not work for delayed logging because transactions are not
  597. written directly into the log buffers. Hence some other method of sequencing
  598. transactions is required.
  599. As discussed in the checkpoint section, delayed logging uses per-checkpoint
  600. contexts, and as such it is simple to assign a sequence number to each
  601. checkpoint. Because the switching of checkpoint contexts must be done
  602. atomically, it is simple to ensure that each new context has a monotonically
  603. increasing sequence number assigned to it without the need for an external
  604. atomic counter - we can just take the current context sequence number and add
  605. one to it for the new context.
  606. Then, instead of assigning a log buffer LSN to the transaction commit LSN
  607. during the commit, we can assign the current checkpoint sequence. This allows
  608. operations that track transactions that have not yet completed know what
  609. checkpoint sequence needs to be committed before they can continue. As a
  610. result, the code that forces the log to a specific LSN now needs to ensure that
  611. the log forces to a specific checkpoint.
  612. To ensure that we can do this, we need to track all the checkpoint contexts
  613. that are currently committing to the log. When we flush a checkpoint, the
  614. context gets added to a "committing" list which can be searched. When a
  615. checkpoint commit completes, it is removed from the committing list. Because
  616. the checkpoint context records the LSN of the commit record for the checkpoint,
  617. we can also wait on the log buffer that contains the commit record, thereby
  618. using the existing log force mechanisms to execute synchronous forces.
  619. It should be noted that the synchronous forces may need to be extended with
  620. mitigation algorithms similar to the current log buffer code to allow
  621. aggregation of multiple synchronous transactions if there are already
  622. synchronous transactions being flushed. Investigation of the performance of the
  623. current design is needed before making any decisions here.
  624. The main concern with log forces is to ensure that all the previous checkpoints
  625. are also committed to disk before the one we need to wait for. Therefore we
  626. need to check that all the prior contexts in the committing list are also
  627. complete before waiting on the one we need to complete. We do this
  628. synchronisation in the log force code so that we don't need to wait anywhere
  629. else for such serialisation - it only matters when we do a log force.
  630. The only remaining complexity is that a log force now also has to handle the
  631. case where the forcing sequence number is the same as the current context. That
  632. is, we need to flush the CIL and potentially wait for it to complete. This is a
  633. simple addition to the existing log forcing code to check the sequence numbers
  634. and push if required. Indeed, placing the current sequence checkpoint flush in
  635. the log force code enables the current mechanism for issuing synchronous
  636. transactions to remain untouched (i.e. commit an asynchronous transaction, then
  637. force the log at the LSN of that transaction) and so the higher level code
  638. behaves the same regardless of whether delayed logging is being used or not.
  639. Delayed Logging: Checkpoint Log Space Accounting
  640. ------------------------------------------------
  641. The big issue for a checkpoint transaction is the log space reservation for the
  642. transaction. We don't know how big a checkpoint transaction is going to be
  643. ahead of time, nor how many log buffers it will take to write out, nor the
  644. number of split log vector regions are going to be used. We can track the
  645. amount of log space required as we add items to the commit item list, but we
  646. still need to reserve the space in the log for the checkpoint.
  647. A typical transaction reserves enough space in the log for the worst case space
  648. usage of the transaction. The reservation accounts for log record headers,
  649. transaction and region headers, headers for split regions, buffer tail padding,
  650. etc. as well as the actual space for all the changed metadata in the
  651. transaction. While some of this is fixed overhead, much of it is dependent on
  652. the size of the transaction and the number of regions being logged (the number
  653. of log vectors in the transaction).
  654. An example of the differences would be logging directory changes versus logging
  655. inode changes. If you modify lots of inode cores (e.g. ``chmod -R g+w *``), then
  656. there are lots of transactions that only contain an inode core and an inode log
  657. format structure. That is, two vectors totaling roughly 150 bytes. If we modify
  658. 10,000 inodes, we have about 1.5MB of metadata to write in 20,000 vectors. Each
  659. vector is 12 bytes, so the total to be logged is approximately 1.75MB. In
  660. comparison, if we are logging full directory buffers, they are typically 4KB
  661. each, so we in 1.5MB of directory buffers we'd have roughly 400 buffers and a
  662. buffer format structure for each buffer - roughly 800 vectors or 1.51MB total
  663. space. From this, it should be obvious that a static log space reservation is
  664. not particularly flexible and is difficult to select the "optimal value" for
  665. all workloads.
  666. Further, if we are going to use a static reservation, which bit of the entire
  667. reservation does it cover? We account for space used by the transaction
  668. reservation by tracking the space currently used by the object in the CIL and
  669. then calculating the increase or decrease in space used as the object is
  670. relogged. This allows for a checkpoint reservation to only have to account for
  671. log buffer metadata used such as log header records.
  672. However, even using a static reservation for just the log metadata is
  673. problematic. Typically log record headers use at least 16KB of log space per
  674. 1MB of log space consumed (512 bytes per 32k) and the reservation needs to be
  675. large enough to handle arbitrary sized checkpoint transactions. This
  676. reservation needs to be made before the checkpoint is started, and we need to
  677. be able to reserve the space without sleeping. For a 8MB checkpoint, we need a
  678. reservation of around 150KB, which is a non-trivial amount of space.
  679. A static reservation needs to manipulate the log grant counters - we can take a
  680. permanent reservation on the space, but we still need to make sure we refresh
  681. the write reservation (the actual space available to the transaction) after
  682. every checkpoint transaction completion. Unfortunately, if this space is not
  683. available when required, then the regrant code will sleep waiting for it.
  684. The problem with this is that it can lead to deadlocks as we may need to commit
  685. checkpoints to be able to free up log space (refer back to the description of
  686. rolling transactions for an example of this). Hence we *must* always have
  687. space available in the log if we are to use static reservations, and that is
  688. very difficult and complex to arrange. It is possible to do, but there is a
  689. simpler way.
  690. The simpler way of doing this is tracking the entire log space used by the
  691. items in the CIL and using this to dynamically calculate the amount of log
  692. space required by the log metadata. If this log metadata space changes as a
  693. result of a transaction commit inserting a new memory buffer into the CIL, then
  694. the difference in space required is removed from the transaction that causes
  695. the change. Transactions at this level will *always* have enough space
  696. available in their reservation for this as they have already reserved the
  697. maximal amount of log metadata space they require, and such a delta reservation
  698. will always be less than or equal to the maximal amount in the reservation.
  699. Hence we can grow the checkpoint transaction reservation dynamically as items
  700. are added to the CIL and avoid the need for reserving and regranting log space
  701. up front. This avoids deadlocks and removes a blocking point from the
  702. checkpoint flush code.
  703. As mentioned early, transactions can't grow to more than half the size of the
  704. log. Hence as part of the reservation growing, we need to also check the size
  705. of the reservation against the maximum allowed transaction size. If we reach
  706. the maximum threshold, we need to push the CIL to the log. This is effectively
  707. a "background flush" and is done on demand. This is identical to
  708. a CIL push triggered by a log force, only that there is no waiting for the
  709. checkpoint commit to complete. This background push is checked and executed by
  710. transaction commit code.
  711. If the transaction subsystem goes idle while we still have items in the CIL,
  712. they will be flushed by the periodic log force issued by the xfssyncd. This log
  713. force will push the CIL to disk, and if the transaction subsystem stays idle,
  714. allow the idle log to be covered (effectively marked clean) in exactly the same
  715. manner that is done for the existing logging method. A discussion point is
  716. whether this log force needs to be done more frequently than the current rate
  717. which is once every 30s.
  718. Delayed Logging: Log Item Pinning
  719. ---------------------------------
  720. Currently log items are pinned during transaction commit while the items are
  721. still locked. This happens just after the items are formatted, though it could
  722. be done any time before the items are unlocked. The result of this mechanism is
  723. that items get pinned once for every transaction that is committed to the log
  724. buffers. Hence items that are relogged in the log buffers will have a pin count
  725. for every outstanding transaction they were dirtied in. When each of these
  726. transactions is completed, they will unpin the item once. As a result, the item
  727. only becomes unpinned when all the transactions complete and there are no
  728. pending transactions. Thus the pinning and unpinning of a log item is symmetric
  729. as there is a 1:1 relationship with transaction commit and log item completion.
  730. For delayed logging, however, we have an asymmetric transaction commit to
  731. completion relationship. Every time an object is relogged in the CIL it goes
  732. through the commit process without a corresponding completion being registered.
  733. That is, we now have a many-to-one relationship between transaction commit and
  734. log item completion. The result of this is that pinning and unpinning of the
  735. log items becomes unbalanced if we retain the "pin on transaction commit, unpin
  736. on transaction completion" model.
  737. To keep pin/unpin symmetry, the algorithm needs to change to a "pin on
  738. insertion into the CIL, unpin on checkpoint completion". In other words, the
  739. pinning and unpinning becomes symmetric around a checkpoint context. We have to
  740. pin the object the first time it is inserted into the CIL - if it is already in
  741. the CIL during a transaction commit, then we do not pin it again. Because there
  742. can be multiple outstanding checkpoint contexts, we can still see elevated pin
  743. counts, but as each checkpoint completes the pin count will retain the correct
  744. value according to its context.
  745. Just to make matters slightly more complex, this checkpoint level context
  746. for the pin count means that the pinning of an item must take place under the
  747. CIL commit/flush lock. If we pin the object outside this lock, we cannot
  748. guarantee which context the pin count is associated with. This is because of
  749. the fact pinning the item is dependent on whether the item is present in the
  750. current CIL or not. If we don't pin the CIL first before we check and pin the
  751. object, we have a race with CIL being flushed between the check and the pin
  752. (or not pinning, as the case may be). Hence we must hold the CIL flush/commit
  753. lock to guarantee that we pin the items correctly.
  754. Delayed Logging: Concurrent Scalability
  755. ---------------------------------------
  756. A fundamental requirement for the CIL is that accesses through transaction
  757. commits must scale to many concurrent commits. The current transaction commit
  758. code does not break down even when there are transactions coming from 2048
  759. processors at once. The current transaction code does not go any faster than if
  760. there was only one CPU using it, but it does not slow down either.
  761. As a result, the delayed logging transaction commit code needs to be designed
  762. for concurrency from the ground up. It is obvious that there are serialisation
  763. points in the design - the three important ones are:
  764. 1. Locking out new transaction commits while flushing the CIL
  765. 2. Adding items to the CIL and updating item space accounting
  766. 3. Checkpoint commit ordering
  767. Looking at the transaction commit and CIL flushing interactions, it is clear
  768. that we have a many-to-one interaction here. That is, the only restriction on
  769. the number of concurrent transactions that can be trying to commit at once is
  770. the amount of space available in the log for their reservations. The practical
  771. limit here is in the order of several hundred concurrent transactions for a
  772. 128MB log, which means that it is generally one per CPU in a machine.
  773. The amount of time a transaction commit needs to hold out a flush is a
  774. relatively long period of time - the pinning of log items needs to be done
  775. while we are holding out a CIL flush, so at the moment that means it is held
  776. across the formatting of the objects into memory buffers (i.e. while memcpy()s
  777. are in progress). Ultimately a two pass algorithm where the formatting is done
  778. separately to the pinning of objects could be used to reduce the hold time of
  779. the transaction commit side.
  780. Because of the number of potential transaction commit side holders, the lock
  781. really needs to be a sleeping lock - if the CIL flush takes the lock, we do not
  782. want every other CPU in the machine spinning on the CIL lock. Given that
  783. flushing the CIL could involve walking a list of tens of thousands of log
  784. items, it will get held for a significant time and so spin contention is a
  785. significant concern. Preventing lots of CPUs spinning doing nothing is the
  786. main reason for choosing a sleeping lock even though nothing in either the
  787. transaction commit or CIL flush side sleeps with the lock held.
  788. It should also be noted that CIL flushing is also a relatively rare operation
  789. compared to transaction commit for asynchronous transaction workloads - only
  790. time will tell if using a read-write semaphore for exclusion will limit
  791. transaction commit concurrency due to cache line bouncing of the lock on the
  792. read side.
  793. The second serialisation point is on the transaction commit side where items
  794. are inserted into the CIL. Because transactions can enter this code
  795. concurrently, the CIL needs to be protected separately from the above
  796. commit/flush exclusion. It also needs to be an exclusive lock but it is only
  797. held for a very short time and so a spin lock is appropriate here. It is
  798. possible that this lock will become a contention point, but given the short
  799. hold time once per transaction I think that contention is unlikely.
  800. The final serialisation point is the checkpoint commit record ordering code
  801. that is run as part of the checkpoint commit and log force sequencing. The code
  802. path that triggers a CIL flush (i.e. whatever triggers the log force) will enter
  803. an ordering loop after writing all the log vectors into the log buffers but
  804. before writing the commit record. This loop walks the list of committing
  805. checkpoints and needs to block waiting for checkpoints to complete their commit
  806. record write. As a result it needs a lock and a wait variable. Log force
  807. sequencing also requires the same lock, list walk, and blocking mechanism to
  808. ensure completion of checkpoints.
  809. These two sequencing operations can use the mechanism even though the
  810. events they are waiting for are different. The checkpoint commit record
  811. sequencing needs to wait until checkpoint contexts contain a commit LSN
  812. (obtained through completion of a commit record write) while log force
  813. sequencing needs to wait until previous checkpoint contexts are removed from
  814. the committing list (i.e. they've completed). A simple wait variable and
  815. broadcast wakeups (thundering herds) has been used to implement these two
  816. serialisation queues. They use the same lock as the CIL, too. If we see too
  817. much contention on the CIL lock, or too many context switches as a result of
  818. the broadcast wakeups these operations can be put under a new spinlock and
  819. given separate wait lists to reduce lock contention and the number of processes
  820. woken by the wrong event.
  821. Lifecycle Changes
  822. -----------------
  823. The existing log item life cycle is as follows::
  824. 1. Transaction allocate
  825. 2. Transaction reserve
  826. 3. Lock item
  827. 4. Join item to transaction
  828. If not already attached,
  829. Allocate log item
  830. Attach log item to owner item
  831. Attach log item to transaction
  832. 5. Modify item
  833. Record modifications in log item
  834. 6. Transaction commit
  835. Pin item in memory
  836. Format item into log buffer
  837. Write commit LSN into transaction
  838. Unlock item
  839. Attach transaction to log buffer
  840. <log buffer IO dispatched>
  841. <log buffer IO completes>
  842. 7. Transaction completion
  843. Mark log item committed
  844. Insert log item into AIL
  845. Write commit LSN into log item
  846. Unpin log item
  847. 8. AIL traversal
  848. Lock item
  849. Mark log item clean
  850. Flush item to disk
  851. <item IO completion>
  852. 9. Log item removed from AIL
  853. Moves log tail
  854. Item unlocked
  855. Essentially, steps 1-6 operate independently from step 7, which is also
  856. independent of steps 8-9. An item can be locked in steps 1-6 or steps 8-9
  857. at the same time step 7 is occurring, but only steps 1-6 or 8-9 can occur
  858. at the same time. If the log item is in the AIL or between steps 6 and 7
  859. and steps 1-6 are re-entered, then the item is relogged. Only when steps 8-9
  860. are entered and completed is the object considered clean.
  861. With delayed logging, there are new steps inserted into the life cycle::
  862. 1. Transaction allocate
  863. 2. Transaction reserve
  864. 3. Lock item
  865. 4. Join item to transaction
  866. If not already attached,
  867. Allocate log item
  868. Attach log item to owner item
  869. Attach log item to transaction
  870. 5. Modify item
  871. Record modifications in log item
  872. 6. Transaction commit
  873. Pin item in memory if not pinned in CIL
  874. Format item into log vector + buffer
  875. Attach log vector and buffer to log item
  876. Insert log item into CIL
  877. Write CIL context sequence into transaction
  878. Unlock item
  879. <next log force>
  880. 7. CIL push
  881. lock CIL flush
  882. Chain log vectors and buffers together
  883. Remove items from CIL
  884. unlock CIL flush
  885. write log vectors into log
  886. sequence commit records
  887. attach checkpoint context to log buffer
  888. <log buffer IO dispatched>
  889. <log buffer IO completes>
  890. 8. Checkpoint completion
  891. Mark log item committed
  892. Insert item into AIL
  893. Write commit LSN into log item
  894. Unpin log item
  895. 9. AIL traversal
  896. Lock item
  897. Mark log item clean
  898. Flush item to disk
  899. <item IO completion>
  900. 10. Log item removed from AIL
  901. Moves log tail
  902. Item unlocked
  903. From this, it can be seen that the only life cycle differences between the two
  904. logging methods are in the middle of the life cycle - they still have the same
  905. beginning and end and execution constraints. The only differences are in the
  906. committing of the log items to the log itself and the completion processing.
  907. Hence delayed logging should not introduce any constraints on log item
  908. behaviour, allocation or freeing that don't already exist.
  909. As a result of this zero-impact "insertion" of delayed logging infrastructure
  910. and the design of the internal structures to avoid on disk format changes, we
  911. can basically switch between delayed logging and the existing mechanism with a
  912. mount option. Fundamentally, there is no reason why the log manager would not
  913. be able to swap methods automatically and transparently depending on load
  914. characteristics, but this should not be necessary if delayed logging works as
  915. designed.