cacheddiskstoragemanager_test.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  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.(*ManagerError).Type != 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 sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  139. t.Error("Unexpected fetch result:", ret3, err)
  140. return
  141. }
  142. err = cdsm.Update(loc, "test99")
  143. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  144. t.Error("Unexpected update result:", err)
  145. return
  146. }
  147. if err := cdsm.Flush(); err != nil && err.Error() != "Records are still in-use (storagemanagertest/ctest1.db - Records 1)" {
  148. t.Error("Unexpected flush result:", err)
  149. return
  150. }
  151. dsm.physicalSlotsSf.ReleaseInUse(record)
  152. // Flush should now succeed
  153. if err := cdsm.Flush(); err != nil {
  154. t.Error(err)
  155. return
  156. }
  157. if err = cdsm.Close(); err != nil {
  158. t.Error(err)
  159. }
  160. }
  161. func TestCachedDiskStorageManagerTransactions(t *testing.T) {
  162. dsm := NewDiskStorageManager(DBDIR+"/ctest2", false, false, false, true)
  163. if dsm.Name() != "DiskStorageFile:"+DBDIR+"/ctest2" {
  164. t.Error("Unexpected name for DiskStorageManager:", dsm.Name())
  165. return
  166. }
  167. cdsm := NewCachedDiskStorageManager(dsm, 10)
  168. loc, err := cdsm.Insert("test1")
  169. if err != nil {
  170. t.Error(err)
  171. return
  172. }
  173. if err := cdsm.Rollback(); err != nil {
  174. t.Error(err)
  175. return
  176. }
  177. if _, ok := cdsm.cache[loc]; ok {
  178. t.Error("Cache entry should be empty")
  179. return
  180. }
  181. var ret string
  182. if err := cdsm.Fetch(loc, &ret); err.(*ManagerError).Type != ErrSlotNotFound ||
  183. err.Error() != "Slot not found (ByteDiskStorageFile:storagemanagertest/ctest2 - Location:1 18)" {
  184. t.Error("Unexpected fetch result:", err)
  185. return
  186. }
  187. // Put it back
  188. loc2, err := cdsm.Insert("test1")
  189. if err != nil {
  190. t.Error(err)
  191. return
  192. }
  193. if loc != loc2 {
  194. t.Error("Unexpected insert position:", loc, loc2)
  195. return
  196. }
  197. // Check free error
  198. record, err := dsm.physicalSlotsSf.Get(1)
  199. if err != nil {
  200. t.Error(err)
  201. return
  202. }
  203. err = cdsm.Free(loc2)
  204. if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
  205. t.Error("Unexpected free result:", err)
  206. return
  207. }
  208. dsm.physicalSlotsSf.ReleaseInUse(record)
  209. // Check that nothing was lost
  210. if err := cdsm.Fetch(loc2, &ret); err != nil || ret != "test1" {
  211. t.Error("Unexpected fetch result:", ret, err)
  212. return
  213. }
  214. if err := cdsm.Free(loc2); err != nil {
  215. t.Error(err)
  216. return
  217. }
  218. if err := cdsm.Fetch(loc2, &ret); err.(*ManagerError).Type != ErrSlotNotFound {
  219. t.Error("Unexpected fetch result:", err)
  220. return
  221. }
  222. if err = cdsm.Close(); err != nil {
  223. t.Error(err)
  224. }
  225. }
  226. func TestCachedDiskStorageManagerCacheManagement(t *testing.T) {
  227. var ret string
  228. dsm := NewDiskStorageManager(DBDIR+"/ctest3", false, false, true, true)
  229. cdsm := NewCachedDiskStorageManager(dsm, 3)
  230. // Event though the cache is empty make sure we can still retrieve empty entries
  231. entry := cdsm.removeOldestFromCache()
  232. if entry == nil {
  233. t.Error("Unexpected removeOldestFromCache result:", entry)
  234. return
  235. }
  236. // Insert values
  237. loc1, _ := cdsm.Insert("test1")
  238. loc2, _ := cdsm.Insert("test2")
  239. loc3, _ := cdsm.Insert("test3")
  240. loc4, _ := cdsm.Insert("test4")
  241. // Load all entries into the cache
  242. cdsm.Fetch(loc1, &ret)
  243. cdsm.Fetch(loc2, &ret)
  244. cdsm.Fetch(loc3, &ret)
  245. // Make sure all cache entries are there
  246. if _, ok := cdsm.cache[loc1]; !ok {
  247. t.Error("Cache entry should be available")
  248. return
  249. }
  250. if _, ok := cdsm.cache[loc2]; !ok {
  251. t.Error("Cache entry should be available")
  252. return
  253. }
  254. if _, ok := cdsm.cache[loc3]; !ok {
  255. t.Error("Cache entry should be available")
  256. return
  257. }
  258. // Now fetch one more and see that the oldest entry gets removed
  259. cdsm.Fetch(loc4, &ret)
  260. if _, ok := cdsm.cache[loc1]; ok {
  261. t.Error("Cache entry should not be available")
  262. return
  263. }
  264. // Check that the last accessed entry is on the last position in the list
  265. if cdsm.lastentry.location != loc4 {
  266. t.Error("Unexpected last entry:", cdsm.firstentry.location)
  267. return
  268. }
  269. cdsm.Fetch(loc2, &ret)
  270. if cdsm.lastentry.location != loc2 {
  271. t.Error("Unexpected last entry:", cdsm.firstentry.location)
  272. return
  273. }
  274. if cdsm.firstentry.location != loc3 {
  275. t.Error("Unexpected first entry:", cdsm.firstentry.location)
  276. return
  277. }
  278. record, err := dsm.physicalSlotsSf.Get(1)
  279. if err != nil {
  280. t.Error(err)
  281. return
  282. }
  283. // Check we get an error when attempting to update the physical record
  284. // because we want to remove an entry from the list
  285. cdsm.Update(loc3, "test9")
  286. cdsm.Update(loc2, "test9")
  287. cdsm.Update(loc4, "test9")
  288. if cdsm.firstentry.location != loc3 {
  289. t.Error("Unexpected first entry:", cdsm.firstentry.location)
  290. return
  291. }
  292. dsm.physicalSlotsSf.ReleaseInUse(record)
  293. entry = cdsm.removeOldestFromCache()
  294. if entry.location != loc3 {
  295. t.Error("Unexpected removeOldestFromCache result:", entry, err)
  296. return
  297. }
  298. if err = cdsm.Close(); err != nil {
  299. t.Error(err)
  300. }
  301. }