You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

271 lines
5.6 KiB

  1. // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
  2. // All rights reserved.
  3. //
  4. // Use of this source code is governed by a BSD-style license that can be
  5. // found in the LICENSE file.
  6. package leveldb
  7. import (
  8. "fmt"
  9. "sync/atomic"
  10. "github.com/syndtr/goleveldb/leveldb/journal"
  11. "github.com/syndtr/goleveldb/leveldb/storage"
  12. )
  13. // Logging.
  14. type dropper struct {
  15. s *session
  16. fd storage.FileDesc
  17. }
  18. func (d dropper) Drop(err error) {
  19. if e, ok := err.(*journal.ErrCorrupted); ok {
  20. d.s.logf("journal@drop %s-%d S·%s %q", d.fd.Type, d.fd.Num, shortenb(e.Size), e.Reason)
  21. } else {
  22. d.s.logf("journal@drop %s-%d %q", d.fd.Type, d.fd.Num, err)
  23. }
  24. }
  25. func (s *session) log(v ...interface{}) { s.stor.Log(fmt.Sprint(v...)) }
  26. func (s *session) logf(format string, v ...interface{}) { s.stor.Log(fmt.Sprintf(format, v...)) }
  27. // File utils.
  28. func (s *session) newTemp() storage.FileDesc {
  29. num := atomic.AddInt64(&s.stTempFileNum, 1) - 1
  30. return storage.FileDesc{storage.TypeTemp, num}
  31. }
  32. func (s *session) addFileRef(fd storage.FileDesc, ref int) int {
  33. ref += s.fileRef[fd.Num]
  34. if ref > 0 {
  35. s.fileRef[fd.Num] = ref
  36. } else if ref == 0 {
  37. delete(s.fileRef, fd.Num)
  38. } else {
  39. panic(fmt.Sprintf("negative ref: %v", fd))
  40. }
  41. return ref
  42. }
  43. // Session state.
  44. // Get current version. This will incr version ref, must call
  45. // version.release (exactly once) after use.
  46. func (s *session) version() *version {
  47. s.vmu.Lock()
  48. defer s.vmu.Unlock()
  49. s.stVersion.incref()
  50. return s.stVersion
  51. }
  52. func (s *session) tLen(level int) int {
  53. s.vmu.Lock()
  54. defer s.vmu.Unlock()
  55. return s.stVersion.tLen(level)
  56. }
  57. // Set current version to v.
  58. func (s *session) setVersion(v *version) {
  59. s.vmu.Lock()
  60. defer s.vmu.Unlock()
  61. // Hold by session. It is important to call this first before releasing
  62. // current version, otherwise the still used files might get released.
  63. v.incref()
  64. if s.stVersion != nil {
  65. // Release current version.
  66. s.stVersion.releaseNB()
  67. }
  68. s.stVersion = v
  69. }
  70. // Get current unused file number.
  71. func (s *session) nextFileNum() int64 {
  72. return atomic.LoadInt64(&s.stNextFileNum)
  73. }
  74. // Set current unused file number to num.
  75. func (s *session) setNextFileNum(num int64) {
  76. atomic.StoreInt64(&s.stNextFileNum, num)
  77. }
  78. // Mark file number as used.
  79. func (s *session) markFileNum(num int64) {
  80. nextFileNum := num + 1
  81. for {
  82. old, x := s.stNextFileNum, nextFileNum
  83. if old > x {
  84. x = old
  85. }
  86. if atomic.CompareAndSwapInt64(&s.stNextFileNum, old, x) {
  87. break
  88. }
  89. }
  90. }
  91. // Allocate a file number.
  92. func (s *session) allocFileNum() int64 {
  93. return atomic.AddInt64(&s.stNextFileNum, 1) - 1
  94. }
  95. // Reuse given file number.
  96. func (s *session) reuseFileNum(num int64) {
  97. for {
  98. old, x := s.stNextFileNum, num
  99. if old != x+1 {
  100. x = old
  101. }
  102. if atomic.CompareAndSwapInt64(&s.stNextFileNum, old, x) {
  103. break
  104. }
  105. }
  106. }
  107. // Set compaction ptr at given level; need external synchronization.
  108. func (s *session) setCompPtr(level int, ik internalKey) {
  109. if level >= len(s.stCompPtrs) {
  110. newCompPtrs := make([]internalKey, level+1)
  111. copy(newCompPtrs, s.stCompPtrs)
  112. s.stCompPtrs = newCompPtrs
  113. }
  114. s.stCompPtrs[level] = append(internalKey{}, ik...)
  115. }
  116. // Get compaction ptr at given level; need external synchronization.
  117. func (s *session) getCompPtr(level int) internalKey {
  118. if level >= len(s.stCompPtrs) {
  119. return nil
  120. }
  121. return s.stCompPtrs[level]
  122. }
  123. // Manifest related utils.
  124. // Fill given session record obj with current states; need external
  125. // synchronization.
  126. func (s *session) fillRecord(r *sessionRecord, snapshot bool) {
  127. r.setNextFileNum(s.nextFileNum())
  128. if snapshot {
  129. if !r.has(recJournalNum) {
  130. r.setJournalNum(s.stJournalNum)
  131. }
  132. if !r.has(recSeqNum) {
  133. r.setSeqNum(s.stSeqNum)
  134. }
  135. for level, ik := range s.stCompPtrs {
  136. if ik != nil {
  137. r.addCompPtr(level, ik)
  138. }
  139. }
  140. r.setComparer(s.icmp.uName())
  141. }
  142. }
  143. // Mark if record has been committed, this will update session state;
  144. // need external synchronization.
  145. func (s *session) recordCommited(rec *sessionRecord) {
  146. if rec.has(recJournalNum) {
  147. s.stJournalNum = rec.journalNum
  148. }
  149. if rec.has(recPrevJournalNum) {
  150. s.stPrevJournalNum = rec.prevJournalNum
  151. }
  152. if rec.has(recSeqNum) {
  153. s.stSeqNum = rec.seqNum
  154. }
  155. for _, r := range rec.compPtrs {
  156. s.setCompPtr(r.level, internalKey(r.ikey))
  157. }
  158. }
  159. // Create a new manifest file; need external synchronization.
  160. func (s *session) newManifest(rec *sessionRecord, v *version) (err error) {
  161. fd := storage.FileDesc{storage.TypeManifest, s.allocFileNum()}
  162. writer, err := s.stor.Create(fd)
  163. if err != nil {
  164. return
  165. }
  166. jw := journal.NewWriter(writer)
  167. if v == nil {
  168. v = s.version()
  169. defer v.release()
  170. }
  171. if rec == nil {
  172. rec = &sessionRecord{}
  173. }
  174. s.fillRecord(rec, true)
  175. v.fillRecord(rec)
  176. defer func() {
  177. if err == nil {
  178. s.recordCommited(rec)
  179. if s.manifest != nil {
  180. s.manifest.Close()
  181. }
  182. if s.manifestWriter != nil {
  183. s.manifestWriter.Close()
  184. }
  185. if !s.manifestFd.Zero() {
  186. s.stor.Remove(s.manifestFd)
  187. }
  188. s.manifestFd = fd
  189. s.manifestWriter = writer
  190. s.manifest = jw
  191. } else {
  192. writer.Close()
  193. s.stor.Remove(fd)
  194. s.reuseFileNum(fd.Num)
  195. }
  196. }()
  197. w, err := jw.Next()
  198. if err != nil {
  199. return
  200. }
  201. err = rec.encode(w)
  202. if err != nil {
  203. return
  204. }
  205. err = jw.Flush()
  206. if err != nil {
  207. return
  208. }
  209. err = s.stor.SetMeta(fd)
  210. return
  211. }
  212. // Flush record to disk.
  213. func (s *session) flushManifest(rec *sessionRecord) (err error) {
  214. s.fillRecord(rec, false)
  215. w, err := s.manifest.Next()
  216. if err != nil {
  217. return
  218. }
  219. err = rec.encode(w)
  220. if err != nil {
  221. return
  222. }
  223. err = s.manifest.Flush()
  224. if err != nil {
  225. return
  226. }
  227. if !s.o.GetNoSync() {
  228. err = s.manifestWriter.Sync()
  229. if err != nil {
  230. return
  231. }
  232. }
  233. s.recordCommited(rec)
  234. return
  235. }