physicalslotmanager_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  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 slotting
  11. import (
  12. "bufio"
  13. "bytes"
  14. "fmt"
  15. "testing"
  16. "devt.de/krotik/eliasdb/storage/file"
  17. "devt.de/krotik/eliasdb/storage/paging"
  18. "devt.de/krotik/eliasdb/storage/paging/view"
  19. "devt.de/krotik/eliasdb/storage/slotting/pageview"
  20. "devt.de/krotik/eliasdb/storage/util"
  21. )
  22. func TestPhysicalSlotManager(t *testing.T) {
  23. sf, err := file.NewDefaultStorageFile(DBDIR+"/test5_data", false)
  24. if err != nil {
  25. t.Error(err.Error())
  26. return
  27. }
  28. psf, err := paging.NewPagedStorageFile(sf)
  29. if err != nil {
  30. t.Error(err)
  31. return
  32. }
  33. fsf, err := file.NewDefaultStorageFile(DBDIR+"/test5_free", false)
  34. if err != nil {
  35. t.Error(err.Error())
  36. return
  37. }
  38. fpsf, err := paging.NewPagedStorageFile(fsf)
  39. if err != nil {
  40. t.Error(err)
  41. return
  42. }
  43. psm := NewPhysicalSlotManager(psf, fpsf, false)
  44. // Build up a data array
  45. arr := make([]byte, 9000)
  46. for i := 0; i < 9000; i++ {
  47. arr[i] = byte(i%5) + 1
  48. }
  49. arr2 := make([]byte, 9000)
  50. for i := 0; i < 9000; i++ {
  51. arr2[i] = byte(i%5) + 5
  52. }
  53. loc, err := psm.Insert(arr, 1, 8999)
  54. if err != nil {
  55. t.Error(err)
  56. return
  57. }
  58. // Location should be beginning of the first record
  59. //checkLocation(t, loc, 1, 20)
  60. // Read back the written data
  61. var b bytes.Buffer
  62. buf := bufio.NewWriter(&b)
  63. if err := psm.Fetch(loc, buf); err != nil {
  64. t.Error("Unexpected read result:", err)
  65. return
  66. }
  67. buf.Flush()
  68. str1 := fmt.Sprint(b.Bytes())
  69. str2 := fmt.Sprint(arr[1:])
  70. if str1 != str2 {
  71. t.Error("Unexpected result reading back what was written")
  72. return
  73. }
  74. loc, err = psm.Update(loc, arr2, 0, 9000)
  75. if err != nil {
  76. t.Error(err)
  77. return
  78. }
  79. // Location should have changed now
  80. checkLocation(t, loc, 3, 871)
  81. // Make sure the new free slots are known
  82. psm.Flush()
  83. // Insert new data - the manager should reuse the previous location
  84. loc, err = psm.Insert(arr2, 1, 8999)
  85. if err != nil {
  86. t.Error(err)
  87. return
  88. }
  89. checkLocation(t, loc, 1, 20)
  90. if err := psm.Free(loc); err != nil {
  91. t.Error(err)
  92. return
  93. }
  94. if err := psm.Flush(); err != nil {
  95. t.Error(err)
  96. return
  97. }
  98. // Test error cases
  99. testInsertPanic(t, psm)
  100. record, err := fsf.Get(1)
  101. if err != nil {
  102. t.Error(err)
  103. return
  104. }
  105. _, err = psm.Insert(make([]byte, 1), 0, 1)
  106. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  107. t.Error("Unexpected insert result:", err)
  108. return
  109. }
  110. fsf.ReleaseInUse(record)
  111. err = psm.Free(util.PackLocation(0, 20))
  112. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  113. t.Error("Unexpected free result:", err)
  114. return
  115. }
  116. record, err = sf.Get(5)
  117. if err != nil {
  118. t.Error(err)
  119. return
  120. }
  121. _, err = psm.allocate(10)
  122. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  123. t.Error("Unexpected allocate result:", err)
  124. return
  125. }
  126. sf.ReleaseInUse(record)
  127. record, err = sf.Get(1)
  128. if err != nil {
  129. t.Error(err)
  130. return
  131. }
  132. // This slot shot be free on page 1
  133. _, err = psm.Insert(arr2, 1, 8999)
  134. // The insert should have failed. The allocated space
  135. // for it should have been send back to the free manager
  136. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  137. t.Error("Unexpected insert result:", err)
  138. return
  139. }
  140. sf.ReleaseInUse(record)
  141. // This should write the recovered free location
  142. // back to the free manager
  143. psm.Flush()
  144. record, err = sf.Get(2)
  145. if err != nil {
  146. t.Error(err)
  147. return
  148. }
  149. _, err = psm.Insert(arr2, 1, 8999)
  150. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  151. t.Error("Unexpected update result:", err)
  152. return
  153. }
  154. sf.ReleaseInUse(record)
  155. checkLocation(t, loc, 1, 20)
  156. // Write the free data which has been declared during the
  157. // last failed call to disk
  158. psm.Flush()
  159. loc, err = psm.Insert(arr2, 1, 8999)
  160. if err != nil {
  161. t.Error("Unexpected insert result:", err)
  162. return
  163. }
  164. checkLocation(t, loc, 1, 20)
  165. record, err = sf.Get(1)
  166. if err != nil {
  167. t.Error(err)
  168. return
  169. }
  170. _, err = psm.Update(loc, arr2, 1, 8999)
  171. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  172. t.Error("Unexpected update result:", err)
  173. return
  174. }
  175. sf.ReleaseInUse(record)
  176. record, err = sf.Get(2)
  177. if err != nil {
  178. t.Error(err)
  179. return
  180. }
  181. _, err = psm.Update(loc, arr2, 1, 8999)
  182. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  183. t.Error("Unexpected update result:", err)
  184. return
  185. }
  186. sf.ReleaseInUse(record)
  187. record, err = sf.Get(5)
  188. if err != nil {
  189. t.Error(err)
  190. return
  191. }
  192. _, err = psm.Update(loc, arr2, 0, 9000)
  193. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  194. t.Error("Unexpected update result:", err)
  195. return
  196. }
  197. sf.ReleaseInUse(record)
  198. record, err = sf.Get(5)
  199. if err != nil {
  200. t.Error(err)
  201. return
  202. }
  203. _, err = psm.Update(loc, arr2, 0, 9000)
  204. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  205. t.Error("Unexpected update result:", err)
  206. return
  207. }
  208. sf.ReleaseInUse(record)
  209. if err := psf.Close(); err != nil {
  210. t.Error(err)
  211. return
  212. }
  213. if err := fpsf.Close(); err != nil {
  214. t.Error(err)
  215. return
  216. }
  217. }
  218. func testInsertPanic(t *testing.T, psm *PhysicalSlotManager) {
  219. defer func() {
  220. if r := recover(); r == nil {
  221. t.Error("Inserting 0 bytes did not cause a panic.")
  222. }
  223. }()
  224. psm.Insert(make([]byte, 0), 0, 0)
  225. }
  226. func TestPhysicalSlotManagerReadWrite(t *testing.T) {
  227. sf, err := file.NewDefaultStorageFile(DBDIR+"/test4_data", false)
  228. if err != nil {
  229. t.Error(err.Error())
  230. return
  231. }
  232. psf, err := paging.NewPagedStorageFile(sf)
  233. if err != nil {
  234. t.Error(err)
  235. return
  236. }
  237. fsf, err := file.NewDefaultStorageFile(DBDIR+"/test4_free", false)
  238. if err != nil {
  239. t.Error(err.Error())
  240. return
  241. }
  242. fpsf, err := paging.NewPagedStorageFile(fsf)
  243. if err != nil {
  244. t.Error(err)
  245. return
  246. }
  247. psm := NewPhysicalSlotManager(psf, fpsf, false)
  248. // Allocate some space
  249. loc1, err := psm.allocateNew(10000, 0)
  250. if err != nil {
  251. t.Error(err)
  252. return
  253. }
  254. // Expected offset is the beginning of page 1
  255. checkLocation(t, loc1, 1, 20)
  256. // Allocate some more space
  257. loc2, err := psm.allocateNew(10, 3)
  258. if err != nil {
  259. t.Error(err)
  260. return
  261. }
  262. // Expected offset is on page 3
  263. checkLocation(t, loc2, 3, 1872)
  264. // Build up a data array
  265. arr := make([]byte, 9000)
  266. for i := 0; i < 9000; i++ {
  267. arr[i] = byte(i%5) + 1
  268. }
  269. // Now write the data array in the allocated space
  270. if err := psm.write(loc1, arr, 1, 8999); err != nil {
  271. t.Error("Unexpected write result:", err)
  272. return
  273. }
  274. // Now check the actual written data
  275. record, err := sf.Get(1)
  276. if err != nil {
  277. t.Error(err)
  278. return
  279. }
  280. sf.ReleaseInUse(record)
  281. // Slot size header should be 10000 available and 8999 current
  282. if asize := util.AvailableSize(record, 20); asize != 10000 {
  283. t.Error("Unexpected available size:", asize)
  284. return
  285. }
  286. if csize := util.CurrentSize(record, 20); csize != 8999 {
  287. t.Error("Unexpected current size:", csize)
  288. return
  289. }
  290. // Check the beginning of the written data
  291. if wdata := record.ReadUInt16(24); wdata != 0x0203 {
  292. t.Error("Unexpected beginning of written data:", wdata)
  293. return
  294. }
  295. record, err = sf.Get(2)
  296. if err != nil {
  297. t.Error(err)
  298. return
  299. }
  300. sf.ReleaseInUse(record)
  301. // Check that the second page is a full data page
  302. pv := pageview.NewDataPage(record)
  303. if of := pv.OffsetFirst(); of != 0 {
  304. t.Error("Unexpected first offset:", of)
  305. return
  306. }
  307. if record.ReadSingleByte(20) != 0x04 || record.ReadSingleByte(4095) != 0x04 {
  308. t.Error("Unexpected record data:", record)
  309. return
  310. }
  311. record, err = sf.Get(3)
  312. if err != nil {
  313. t.Error(err)
  314. return
  315. }
  316. sf.ReleaseInUse(record)
  317. // Check that the last page is partially written
  318. // Offset should be the location of the second allocated data block
  319. pv = pageview.NewDataPage(record)
  320. if of := pv.OffsetFirst(); of != 1872 {
  321. t.Error("Unexpected first offset:", of)
  322. return
  323. }
  324. // Data should end with 5 on the following location
  325. // 8999 data written + 4 byte header = 9003 bytes written
  326. // 9003 - 4076 page1 - 4076 page2 = 851 bytes for the last page
  327. // 20 bytes header + 851 written bytes = 871 bytes (offset 870)
  328. if lastByte := record.ReadSingleByte(870); lastByte != 5 {
  329. t.Error("Unexpected last byte:", lastByte)
  330. return
  331. }
  332. if lastByteAfter := record.ReadSingleByte(871); lastByteAfter != 0 {
  333. t.Error("Unexpected byte after last byte:", lastByteAfter)
  334. return
  335. }
  336. // Read back the written data
  337. var b bytes.Buffer
  338. buf := bufio.NewWriter(&b)
  339. if err := psm.Fetch(loc1, buf); err != nil {
  340. t.Error("Unexpected read result:", err)
  341. return
  342. }
  343. buf.Flush()
  344. str1 := fmt.Sprint(b.Bytes())
  345. str2 := fmt.Sprint(arr[1:])
  346. if str1 != str2 {
  347. t.Error("Unexpected result reading back what was written")
  348. return
  349. }
  350. // Test some special cases
  351. record, err = sf.Get(util.LocationRecord(loc2))
  352. if err != nil {
  353. t.Error(err)
  354. return
  355. }
  356. err = psm.write(loc2, make([]byte, 0), 0, 0)
  357. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  358. t.Error("Unexpected write result:", err)
  359. }
  360. err = psm.Fetch(loc2, buf)
  361. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  362. t.Error("Unexpected read result:", err)
  363. return
  364. }
  365. sf.ReleaseInUse(record)
  366. if err := psm.write(loc2, make([]byte, 0), 0, 0); err != nil {
  367. t.Error("Unexpected write result:", err)
  368. }
  369. var b2 bytes.Buffer
  370. buf = bufio.NewWriter(&b2)
  371. if err := psm.Fetch(loc2, buf); err != nil {
  372. t.Error("Unexpected read result:", err)
  373. return
  374. }
  375. buf.Flush()
  376. if len(b2.Bytes()) != 0 {
  377. t.Error("Nothing should have been read back")
  378. return
  379. }
  380. if asize := util.AvailableSize(record, int(util.LocationOffset(loc2))); asize != 10 {
  381. t.Error("Unexpected available size:", asize)
  382. return
  383. }
  384. if csize := util.CurrentSize(record, int(util.LocationOffset(loc2))); csize != 0 {
  385. t.Error("Unexpected current size:", csize)
  386. return
  387. }
  388. record, err = sf.Get(3)
  389. if err != nil {
  390. t.Error(err)
  391. return
  392. }
  393. err = psm.write(loc2, make([]byte, 10000), 0, 9999)
  394. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  395. t.Error("Unexpected write result:", err)
  396. }
  397. err = psm.Fetch(loc2, buf)
  398. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  399. t.Error("Unexpected read result:", err)
  400. return
  401. }
  402. sf.ReleaseInUse(record)
  403. loc3, err := psm.allocateNew(10000, 3)
  404. if err != nil {
  405. t.Error(err)
  406. return
  407. }
  408. record, err = sf.Get(5)
  409. if err != nil {
  410. t.Error(err)
  411. return
  412. }
  413. err = psm.write(loc3, make([]byte, 10000), 0, 9999)
  414. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  415. t.Error("Unexpected write result:", err)
  416. }
  417. err = psm.Fetch(loc3, buf)
  418. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  419. t.Error("Unexpected read result:", err)
  420. return
  421. }
  422. sf.ReleaseInUse(record)
  423. if err := psf.Close(); err != nil {
  424. t.Error(err)
  425. return
  426. }
  427. if err := fpsf.Close(); err != nil {
  428. t.Error(err)
  429. return
  430. }
  431. }
  432. func TestPhysicalSlotManagerAllocateNew(t *testing.T) {
  433. sf, err := file.NewDefaultStorageFile(DBDIR+"/test3_data", false)
  434. if err != nil {
  435. t.Error(err.Error())
  436. return
  437. }
  438. psf, err := paging.NewPagedStorageFile(sf)
  439. if err != nil {
  440. t.Error(err)
  441. return
  442. }
  443. fsf, err := file.NewDefaultStorageFile(DBDIR+"/test3_free", false)
  444. if err != nil {
  445. t.Error(err.Error())
  446. return
  447. }
  448. fpsf, err := paging.NewPagedStorageFile(fsf)
  449. if err != nil {
  450. t.Error(err)
  451. return
  452. }
  453. psm := NewPhysicalSlotManager(psf, fpsf, false)
  454. // Check the simple case
  455. size := util.NormalizeSlotSize(500)
  456. // Error case new allocated page is already in use
  457. record, err := sf.Get(1)
  458. if err != nil {
  459. t.Error(err)
  460. return
  461. }
  462. _, err = psm.allocateNew(size, 0)
  463. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  464. t.Error(err)
  465. return
  466. }
  467. sf.ReleaseInUse(record)
  468. // Test first allocation
  469. loc, err := psm.allocateNew(size, 0)
  470. if err != nil {
  471. t.Error(err)
  472. return
  473. }
  474. checkLocation(t, loc, 1, pageview.OffsetData)
  475. // Error case existing page is already in use
  476. record, err = sf.Get(1)
  477. if err != nil {
  478. t.Error(err)
  479. return
  480. }
  481. _, err = psm.allocateNew(10, 1)
  482. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  483. t.Error(err)
  484. return
  485. }
  486. sf.ReleaseInUse(record)
  487. loc, err = psm.allocateNew(10, 1)
  488. if err != nil {
  489. t.Error(err)
  490. return
  491. }
  492. // Expected offset is 524
  493. // Page header (20) + prev. allocated data (500) + SizeInfoSize header (4)
  494. exploc := pageview.OffsetData + 500 + util.SizeInfoSize
  495. if exploc != 524 {
  496. t.Error("Expected location should be 532 but is:", exploc)
  497. return
  498. }
  499. checkLocation(t, loc, 1, uint16(exploc))
  500. loc, err = psm.allocateNew(7000, 1)
  501. if err != nil {
  502. t.Error(err)
  503. return
  504. }
  505. // Expected offset is 538
  506. // Last offset (524) + prev. allocated data (10) + SizeInfoSize header (4)
  507. checkLocation(t, loc, 1, 538)
  508. // Last page is now page 2
  509. loc, err = psm.allocateNew(10, 2)
  510. if err != nil {
  511. t.Error(err)
  512. return
  513. }
  514. // Expected offset is 3466 (+ 1 page)
  515. // Last offset (538) + prev. allocated data (7000) + SizeInfoSize header (4)
  516. // Default size for one record is 4096 - 20 bytes header = 4076
  517. // 7542 - 4076 = 3466
  518. checkLocation(t, loc, 2, 3466)
  519. loc, err = psm.allocateNew(10000, 2)
  520. if err != nil {
  521. t.Error(err)
  522. return
  523. }
  524. // Expected offset is 3480
  525. // Last offset (3466) + prev. allocated data (10) + SizeInfoSize header (4)
  526. checkLocation(t, loc, 2, 3480)
  527. // Last page is now page 5 - This allocation should fill up page 5 exacly
  528. // - allocation should be rounded up by 6
  529. loc, err = psm.allocateNew(2830, 5)
  530. if err != nil {
  531. t.Error(err)
  532. return
  533. }
  534. // Expected offset is 1256 (+ 3 pages)
  535. // Last offset (3480) + prev. allocated data (10000) + SizeInfoSize header (4)
  536. // Default size for one record is 4096 - 20 bytes header = 4076
  537. // 13484 - 4076 - 4076 - 4076 = 1256
  538. checkLocation(t, loc, 5, 1256)
  539. // Since page 5 was filled up we should be now allocated to page 6 at
  540. // the beginning - the next allocation should take up page 6 and 7
  541. loc, err = psm.allocateNew(8147, 5)
  542. if err != nil {
  543. t.Error(err)
  544. return
  545. }
  546. // Expected offset is the beginning of page 6
  547. checkLocation(t, loc, 6, 20)
  548. // With the allocated space we should fill page 7
  549. // Rounded up by 1
  550. if lap := psm.pager.Last(view.TypeDataPage); lap != 7 {
  551. t.Error("Unexpected last allocated page", lap)
  552. return
  553. }
  554. // Since page 7 was filled up completely and its first offset is 0
  555. // the algorithm should allocate a new page.
  556. loc, err = psm.allocateNew(10, 7)
  557. if err != nil {
  558. t.Error(err)
  559. }
  560. // Expected offset is the beginning of page 8
  561. checkLocation(t, loc, 8, 20)
  562. // Construct a page where not enough space is free for an allocation
  563. page, err := psm.pager.AllocatePage(view.TypeDataPage)
  564. if err != nil {
  565. t.Error(err)
  566. return
  567. }
  568. record, err = psm.storagefile.Get(page)
  569. if err != nil {
  570. t.Error(err)
  571. return
  572. }
  573. pv := pageview.NewDataPage(record)
  574. pv.SetOffsetFirst(uint16(4093))
  575. psm.storagefile.ReleaseInUseID(page, true)
  576. loc, err = psm.allocateNew(10, 9)
  577. if err != nil {
  578. t.Error(err)
  579. }
  580. // Expected offset is the beginning of page 10
  581. checkLocation(t, loc, 10, 20)
  582. // Now a two error tests which will cause the page pointers get out of sync
  583. record, err = sf.Get(12)
  584. if err != nil {
  585. t.Error(err)
  586. return
  587. }
  588. _, err = psm.allocateNew(8147, 5)
  589. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  590. t.Error(err)
  591. return
  592. }
  593. sf.ReleaseInUse(record)
  594. // Page 11 was now allocated but not written to
  595. loc, err = psm.allocateNew(10, 9)
  596. if err != nil {
  597. t.Error(err)
  598. }
  599. // Expected offset is the beginning of page 12
  600. checkLocation(t, loc, 12, 20)
  601. record, err = sf.Get(14)
  602. if err != nil {
  603. t.Error(err)
  604. return
  605. }
  606. _, err = psm.allocateNew(8147, 12)
  607. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  608. t.Error(err)
  609. return
  610. }
  611. sf.ReleaseInUse(record)
  612. // Page 13 was now allocated but not written to
  613. loc, err = psm.allocateNew(10, 9)
  614. if err != nil {
  615. t.Error(err)
  616. }
  617. // Expected offset is the beginning of page 14
  618. checkLocation(t, loc, 14, 20)
  619. if err := psf.Close(); err != nil {
  620. t.Error(err)
  621. return
  622. }
  623. if err := fpsf.Close(); err != nil {
  624. t.Error(err)
  625. return
  626. }
  627. }
  628. func checkLocation(t *testing.T, loc uint64, record uint64, offset uint16) {
  629. lrecord := util.LocationRecord(loc)
  630. loffset := util.LocationOffset(loc)
  631. if lrecord != record || loffset != offset {
  632. t.Error("Unexpected location. Expected:", record, offset, "Got:", lrecord, loffset)
  633. }
  634. }