pagedstoragefile.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * EliasDB
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. */
  10. package paging
  11. import (
  12. "errors"
  13. "devt.de/krotik/eliasdb/storage/file"
  14. "devt.de/krotik/eliasdb/storage/paging/view"
  15. )
  16. /*
  17. Common paged storage file related errors
  18. */
  19. var (
  20. ErrFreePage = errors.New("Cannot allocate/free a free page")
  21. ErrHeader = errors.New("Cannot modify header record")
  22. )
  23. /*
  24. PagedStorageFile data structure
  25. */
  26. type PagedStorageFile struct {
  27. storagefile *file.StorageFile // StorageFile which is wrapped
  28. header *PagedStorageFileHeader // Header object
  29. }
  30. /*
  31. NewPagedStorageFile wraps a given StorageFile and returns a PagedStorageFile.
  32. */
  33. func NewPagedStorageFile(storagefile *file.StorageFile) (*PagedStorageFile, error) {
  34. var header *PagedStorageFileHeader
  35. record, err := storagefile.Get(0)
  36. if err != nil {
  37. return nil, err
  38. }
  39. // Check if this is a new header record or not
  40. isnew := record.ReadInt16(0) == 0
  41. header = NewPagedStorageFileHeader(record, isnew)
  42. return &PagedStorageFile{storagefile, header}, nil
  43. }
  44. /*
  45. StorageFile returns the wrapped StorageFile.
  46. */
  47. func (psf *PagedStorageFile) StorageFile() *file.StorageFile {
  48. return psf.storagefile
  49. }
  50. /*
  51. Header returns the header object of this PagedStorageFile.
  52. */
  53. func (psf *PagedStorageFile) Header() *PagedStorageFileHeader {
  54. return psf.header
  55. }
  56. /*
  57. AllocatePage allocates a new page of a specific type.
  58. */
  59. func (psf *PagedStorageFile) AllocatePage(pagetype int16) (uint64, error) {
  60. var record *file.Record
  61. var err error
  62. if pagetype == view.TypeFreePage {
  63. return 0, ErrFreePage
  64. }
  65. // Check first the free list
  66. ptr := psf.header.FirstListElement(view.TypeFreePage)
  67. isnew := ptr == 0
  68. if !isnew {
  69. // If there is something on the free list set the pointer
  70. // for the first item to the second item. The first item
  71. // becomes our newly allocated element.
  72. nextptr, err := psf.Next(ptr)
  73. if err != nil {
  74. return 0, err
  75. }
  76. // Get the record - error checking already done in the
  77. // previous psf.Next call
  78. record, _ = psf.storagefile.Get(ptr)
  79. psf.header.SetFirstListElement(view.TypeFreePage, nextptr)
  80. } else {
  81. // Need to create a new rcord
  82. ptr = psf.header.LastListElement(view.TypeFreePage)
  83. if ptr == 0 {
  84. // If the file is new the first pointer is 1
  85. ptr = 1
  86. }
  87. // Get the record - if it fails we need to return before
  88. // increasing the last list element pointer
  89. record, err = psf.storagefile.Get(ptr)
  90. if err != nil {
  91. return 0, err
  92. }
  93. // The last list element pointer is used to point to the next free record
  94. // it is not actuallz the last element of the list.
  95. psf.header.SetLastListElement(view.TypeFreePage, ptr+1)
  96. }
  97. // Set the view data on the record
  98. var pageview *view.PageView
  99. // Add a temp. page view so we can modify the record
  100. if isnew {
  101. pageview = view.NewPageView(record, pagetype)
  102. } else {
  103. pageview = view.GetPageView(record)
  104. }
  105. oldtail := psf.header.LastListElement(pagetype)
  106. record.ClearData()
  107. pageview.SetType(pagetype)
  108. pageview.SetPrevPage(oldtail)
  109. pageview.SetNextPage(0)
  110. // Check if this page was the first of its type
  111. if oldtail == 0 {
  112. psf.header.SetFirstListElement(pagetype, ptr)
  113. }
  114. // New allocated record is now the new last element
  115. psf.header.SetLastListElement(pagetype, ptr)
  116. // We can release the record now
  117. psf.storagefile.ReleaseInUse(record)
  118. // Need to fix up the pointer of the former previous element
  119. if oldtail != 0 {
  120. record, err = psf.storagefile.Get(oldtail)
  121. if err != nil {
  122. return 0, err
  123. }
  124. pageview = view.GetPageView(record)
  125. pageview.SetNextPage(ptr)
  126. psf.storagefile.ReleaseInUse(record)
  127. }
  128. // Remove temp. page view
  129. record.SetPageView(nil)
  130. return ptr, nil
  131. }
  132. /*
  133. FreePage frees a given page and adds it to the free list.
  134. */
  135. func (psf *PagedStorageFile) FreePage(id uint64) error {
  136. if id == 0 {
  137. return ErrHeader
  138. }
  139. record, err := psf.storagefile.Get(id)
  140. if err != nil {
  141. return err
  142. }
  143. pageview := view.GetPageView(record)
  144. pagetype := pageview.Type()
  145. if pagetype == view.TypeFreePage {
  146. psf.storagefile.ReleaseInUse(record)
  147. return ErrFreePage
  148. }
  149. prev := pageview.PrevPage()
  150. next := pageview.NextPage()
  151. // Put the page to the front of the free list
  152. pageview.SetType(view.TypeFreePage)
  153. pageview.SetNextPage(psf.header.FirstListElement(view.TypeFreePage))
  154. pageview.SetPrevPage(0)
  155. psf.header.SetFirstListElement(view.TypeFreePage, id)
  156. // NOTE The prev pointers will always point to 0 for records in the
  157. // free list. There is no need to update them.
  158. psf.storagefile.ReleaseInUse(record)
  159. // Remove page from its old list - an error in the below leaves
  160. // the lists in an inconsistent state.
  161. if prev != 0 {
  162. record, err = psf.storagefile.Get(prev)
  163. if err != nil {
  164. return err
  165. }
  166. pageview := view.GetPageView(record)
  167. pageview.SetNextPage(next)
  168. psf.storagefile.ReleaseInUse(record)
  169. } else {
  170. psf.header.SetFirstListElement(pagetype, next)
  171. }
  172. if next != 0 {
  173. record, err = psf.storagefile.Get(next)
  174. if err != nil {
  175. return err
  176. }
  177. pageview := view.GetPageView(record)
  178. pageview.SetPrevPage(prev)
  179. psf.storagefile.ReleaseInUse(record)
  180. } else {
  181. psf.header.SetLastListElement(pagetype, prev)
  182. }
  183. return nil
  184. }
  185. /*
  186. First returns the first page of a list of a given type.
  187. */
  188. func (psf *PagedStorageFile) First(pagetype int16) uint64 {
  189. return psf.header.FirstListElement(pagetype)
  190. }
  191. /*
  192. Last returns the first page of a list of a given type.
  193. */
  194. func (psf *PagedStorageFile) Last(pagetype int16) uint64 {
  195. return psf.header.LastListElement(pagetype)
  196. }
  197. /*
  198. Next returns the next page of a given page in a list.
  199. */
  200. func (psf *PagedStorageFile) Next(id uint64) (uint64, error) {
  201. record, err := psf.storagefile.Get(id)
  202. if err != nil {
  203. return 0, err
  204. }
  205. defer psf.storagefile.ReleaseInUse(record)
  206. pageview := view.GetPageView(record)
  207. return pageview.NextPage(), nil
  208. }
  209. /*
  210. Prev returns the previous page of a given page in a list.
  211. */
  212. func (psf *PagedStorageFile) Prev(id uint64) (uint64, error) {
  213. record, err := psf.storagefile.Get(id)
  214. if err != nil {
  215. return 0, err
  216. }
  217. defer psf.storagefile.ReleaseInUse(record)
  218. pageview := view.GetPageView(record)
  219. return pageview.PrevPage(), nil
  220. }
  221. /*
  222. Flush writes all pending data to disk.
  223. */
  224. func (psf *PagedStorageFile) Flush() error {
  225. psf.storagefile.ReleaseInUse(psf.header.record)
  226. if err := psf.storagefile.Flush(); err != nil {
  227. // If an error happens try to recover by putting
  228. // the header record back in use
  229. psf.storagefile.Get(0)
  230. return err
  231. }
  232. // No particular error checking for Get operation as
  233. // it should succeed if the previous Flush was successful.
  234. record, _ := psf.storagefile.Get(0)
  235. psf.header = NewPagedStorageFileHeader(record, false)
  236. return nil
  237. }
  238. /*
  239. Rollback discards all changes which were done after the last flush.
  240. The PageStorageFile object should be discarded if something
  241. goes wrong during a rollback operation.
  242. */
  243. func (psf *PagedStorageFile) Rollback() error {
  244. psf.storagefile.Discard(psf.header.record)
  245. if err := psf.storagefile.Rollback(); err != nil {
  246. // If there is a problem try to get the header record back
  247. // otherwise close operations may fail later
  248. psf.header.record, _ = psf.storagefile.Get(0)
  249. return err
  250. }
  251. // No particular error checking for Get operation as
  252. // it should succeed if the previous Rollback was successful.
  253. record, _ := psf.storagefile.Get(0)
  254. psf.header = NewPagedStorageFileHeader(record, record.ReadInt16(0) == 0)
  255. return nil
  256. }
  257. /*
  258. Close commits all data and closes all physical files.
  259. */
  260. func (psf *PagedStorageFile) Close() error {
  261. if psf.header != nil {
  262. psf.storagefile.ReleaseInUse(psf.header.record)
  263. psf.header = nil
  264. }
  265. if err := psf.storagefile.Close(); err != nil {
  266. return err
  267. }
  268. psf.storagefile = nil
  269. return nil
  270. }