cacheddiskstoragemanager_test.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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 storage
  11. import (
  12. "testing"
  13. "devt.de/krotik/eliasdb/storage/file"
  14. "devt.de/krotik/eliasdb/storage/slotting/pageview"
  15. )
  16. type cachetestobj struct {
  17. Val1 int
  18. Val2 string
  19. }
  20. func TestCachedDiskStorageManager(t *testing.T) {
  21. dsm := NewDiskStorageManager(DBDIR+"/ctest1", false, false, true, true)
  22. if dsm.Name() != "DiskStorageFile:"+DBDIR+"/ctest1" {
  23. t.Error("Unexpected name for DiskStorageManager:", dsm.Name())
  24. return
  25. }
  26. cdsm := NewCachedDiskStorageManager(dsm, 10)
  27. // Test the getter and setter fields
  28. if cdsm.Name() != dsm.Name() {
  29. t.Error("Unexpected result asking for the name")
  30. return
  31. }
  32. if cdsm.Root(RootIDVersion) != dsm.Root(RootIDVersion) || dsm.Root(RootIDVersion) == 0 {
  33. t.Error("Unexpected result asking for the version")
  34. return
  35. }
  36. cdsm.SetRoot(5, 20)
  37. if cdsm.Root(5) != 20 || dsm.Root(5) != 20 {
  38. t.Error("Unexpected result asking for a root")
  39. return
  40. }
  41. // Test the insert which is not cached
  42. testObj1 := &cachetestobj{1, "This is a test"}
  43. testObj2 := &cachetestobj{1, "This is a 7e57"}
  44. loc, err := cdsm.Insert(testObj1)
  45. if err != nil {
  46. t.Error(err)
  47. return
  48. }
  49. // Test getting non-existent entry from cache
  50. if _, err := cdsm.FetchCached(loc + 1); err != ErrNotInCache {
  51. t.Error("Unexpected FetchCached result:", err)
  52. return
  53. }
  54. // Make sure rollback has no effect if the transactions are disabled
  55. cdsm.Rollback()
  56. checkLocation(t, loc, 1, pageview.OffsetTransData)
  57. if _, ok := cdsm.cache[loc]; !ok {
  58. t.Error("Cache entry should not be empty")
  59. return
  60. }
  61. var ret1, ret2 cachetestobj
  62. err = cdsm.Fetch(loc, &ret1)
  63. if ret1.Val2 != "This is a test" || err != nil {
  64. t.Error("Unexpected fetch result:", ret1, err)
  65. return
  66. }
  67. // Check cache entry
  68. if e, ok := cdsm.cache[loc]; !ok || ret1 == e.object ||
  69. e.object.(*cachetestobj).Val2 != "This is a test" {
  70. t.Error("Update should store a copy")
  71. return
  72. }
  73. err = dsm.Fetch(loc, &ret2)
  74. if ret2.Val2 != "This is a test" || err != nil {
  75. t.Error("Unexpected fetch result:", ret2, err)
  76. return
  77. }
  78. // Test the update which is cached
  79. if err := cdsm.Update(loc, testObj2); err != nil {
  80. t.Error(err)
  81. return
  82. }
  83. if testObj2 != cdsm.cache[loc].object {
  84. t.Error("Cache should contain object which was given by update")
  85. return
  86. }
  87. // Check that we have a cache entry
  88. err = cdsm.Fetch(loc, &ret2)
  89. if ret2.Val2 != "This is a 7e57" || err != nil {
  90. t.Error("Unexpected fetch result:", ret2, err)
  91. return
  92. }
  93. // Test writing a different type
  94. if err := cdsm.Update(loc, "bla"); err != nil {
  95. t.Error(err)
  96. return
  97. }
  98. var ret3 string
  99. err = dsm.Fetch(loc, &ret3)
  100. if ret3 != "bla" || err != nil {
  101. t.Error("Unexpected fetch result:", ret3, err)
  102. return
  103. }
  104. // Run update on something which is unknown
  105. loc, err = cdsm.Insert("test66")
  106. if err != nil {
  107. t.Error(err)
  108. return
  109. }
  110. // Here the update should create the cache entry
  111. err = cdsm.Update(loc, "test77")
  112. if err != nil {
  113. t.Error(err)
  114. return
  115. }
  116. var obj interface{}
  117. obj, _ = cdsm.FetchCached(loc)
  118. if obj.(string) != "test77" {
  119. t.Error("Unexpected FetchCached result:", obj)
  120. return
  121. }
  122. err = dsm.Fetch(loc, &ret3)
  123. if ret3 != "test77" || err != nil {
  124. t.Error("Unexpected fetch result:", ret3, err)
  125. return
  126. }
  127. loc, err = dsm.Insert("test88")
  128. if err != nil {
  129. t.Error(err)
  130. return
  131. }
  132. record, err := dsm.physicalSlotsSf.Get(1)
  133. if err != nil {
  134. t.Error(err)
  135. return
  136. }
  137. err = cdsm.Fetch(loc, &ret3)
  138. if err != file.ErrAlreadyInUse {
  139. t.Error("Unexpected fetch result:", ret3, err)
  140. return
  141. }
  142. if err := cdsm.Update(loc, "test99"); err != file.ErrAlreadyInUse {
  143. t.Error("Unexpected update result:", err)
  144. return
  145. }
  146. if err := cdsm.Flush(); err != nil && err.Error() != "Records are still in-use (storagemanagertest/ctest1.db - Records 1)" {
  147. t.Error("Unexpected flush result:", err)
  148. return
  149. }
  150. dsm.physicalSlotsSf.ReleaseInUse(record)
  151. // Flush should now succeed
  152. if err := cdsm.Flush(); err != nil {
  153. t.Error(err)
  154. return
  155. }
  156. if err = cdsm.Close(); err != nil {
  157. t.Error(err)
  158. }
  159. }
  160. func TestCachedDiskStorageManagerTransactions(t *testing.T) {
  161. dsm := NewDiskStorageManager(DBDIR+"/ctest2", false, false, false, true)
  162. if dsm.Name() != "DiskStorageFile:"+DBDIR+"/ctest2" {
  163. t.Error("Unexpected name for DiskStorageManager:", dsm.Name())
  164. return
  165. }
  166. cdsm := NewCachedDiskStorageManager(dsm, 10)
  167. loc, err := cdsm.Insert("test1")
  168. if err != nil {
  169. t.Error(err)
  170. return
  171. }
  172. if err := cdsm.Rollback(); err != nil {
  173. t.Error(err)
  174. return
  175. }
  176. if _, ok := cdsm.cache[loc]; ok {
  177. t.Error("Cache entry should be empty")
  178. return
  179. }
  180. var ret string
  181. if err := cdsm.Fetch(loc, &ret); err != ErrSlotNotFound ||
  182. err.Error() != "Slot not found (ByteDiskStorageFile:storagemanagertest/ctest2 - Location:1 18)" {
  183. t.Error("Unexpected fetch result:", err)
  184. return
  185. }
  186. // Put it back
  187. loc2, err := cdsm.Insert("test1")
  188. if err != nil {
  189. t.Error(err)
  190. return
  191. }
  192. if loc != loc2 {
  193. t.Error("Unexpected insert position:", loc, loc2)
  194. return
  195. }
  196. // Check free error
  197. record, err := dsm.physicalSlotsSf.Get(1)
  198. if err != nil {
  199. t.Error(err)
  200. return
  201. }
  202. if err := cdsm.Free(loc2); err != file.ErrAlreadyInUse {
  203. t.Error("Unexpected free result:", err)
  204. return
  205. }
  206. dsm.physicalSlotsSf.ReleaseInUse(record)
  207. // Check that nothing was lost
  208. if err := cdsm.Fetch(loc2, &ret); err != nil || ret != "test1" {
  209. t.Error("Unexpected fetch result:", ret, err)
  210. return
  211. }
  212. if err := cdsm.Free(loc2); err != nil {
  213. t.Error(err)
  214. return
  215. }
  216. if err := cdsm.Fetch(loc2, &ret); err != ErrSlotNotFound {
  217. t.Error("Unexpected fetch result:", err)
  218. return
  219. }
  220. if err = cdsm.Close(); err != nil {
  221. t.Error(err)
  222. }
  223. }
  224. func TestCachedDiskStorageManagerCacheManagement(t *testing.T) {
  225. var ret string
  226. dsm := NewDiskStorageManager(DBDIR+"/ctest3", false, false, true, true)
  227. cdsm := NewCachedDiskStorageManager(dsm, 3)
  228. // Event though the cache is empty make sure we can still retrieve empty entries
  229. entry := cdsm.removeOldestFromCache()
  230. if entry == nil {
  231. t.Error("Unexpected removeOldestFromCache result:", entry)
  232. return
  233. }
  234. // Insert values
  235. loc1, err := cdsm.Insert("test1")
  236. loc2, err := cdsm.Insert("test2")
  237. loc3, err := cdsm.Insert("test3")
  238. loc4, err := cdsm.Insert("test4")
  239. // Load all entries into the cache
  240. cdsm.Fetch(loc1, &ret)
  241. cdsm.Fetch(loc2, &ret)
  242. cdsm.Fetch(loc3, &ret)
  243. // Make sure all cache entries are there
  244. if _, ok := cdsm.cache[loc1]; !ok {
  245. t.Error("Cache entry should be available")
  246. return
  247. }
  248. if _, ok := cdsm.cache[loc2]; !ok {
  249. t.Error("Cache entry should be available")
  250. return
  251. }
  252. if _, ok := cdsm.cache[loc3]; !ok {
  253. t.Error("Cache entry should be available")
  254. return
  255. }
  256. // Now fetch one more and see that the oldest entry gets removed
  257. cdsm.Fetch(loc4, &ret)
  258. if _, ok := cdsm.cache[loc1]; ok {
  259. t.Error("Cache entry should not be available")
  260. return
  261. }
  262. // Check that the last accessed entry is on the last position in the list
  263. if cdsm.lastentry.location != loc4 {
  264. t.Error("Unexpected last entry:", cdsm.firstentry.location)
  265. return
  266. }
  267. cdsm.Fetch(loc2, &ret)
  268. if cdsm.lastentry.location != loc2 {
  269. t.Error("Unexpected last entry:", cdsm.firstentry.location)
  270. return
  271. }
  272. if cdsm.firstentry.location != loc3 {
  273. t.Error("Unexpected first entry:", cdsm.firstentry.location)
  274. return
  275. }
  276. record, err := dsm.physicalSlotsSf.Get(1)
  277. if err != nil {
  278. t.Error(err)
  279. return
  280. }
  281. // Check we get an error when attempting to update the physical record
  282. // because we want to remove an entry from the list
  283. cdsm.Update(loc3, "test9")
  284. cdsm.Update(loc2, "test9")
  285. cdsm.Update(loc4, "test9")
  286. if cdsm.firstentry.location != loc3 {
  287. t.Error("Unexpected first entry:", cdsm.firstentry.location)
  288. return
  289. }
  290. dsm.physicalSlotsSf.ReleaseInUse(record)
  291. entry = cdsm.removeOldestFromCache()
  292. if entry.location != loc3 {
  293. t.Error("Unexpected removeOldestFromCache result:", entry, err)
  294. return
  295. }
  296. if err = cdsm.Close(); err != nil {
  297. t.Error(err)
  298. }
  299. }