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.

356 lines
10 KiB

12 years ago
12 years ago
12 years ago
7 years ago
12 years ago
9 years ago
10 years ago
12 years ago
12 years ago
7 years ago
6 years ago
7 years ago
7 years ago
7 years ago
12 years ago
12 years ago
12 years ago
7 years ago
7 years ago
12 years ago
7 years ago
7 years ago
12 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
9 years ago
9 years ago
  1. package storage
  2. import (
  3. "errors"
  4. "fmt"
  5. "io"
  6. "os"
  7. "github.com/chrislusf/seaweedfs/weed/glog"
  8. . "github.com/chrislusf/seaweedfs/weed/storage/types"
  9. "github.com/chrislusf/seaweedfs/weed/util"
  10. "math"
  11. )
  12. const (
  13. FlagGzip = 0x01
  14. FlagHasName = 0x02
  15. FlagHasMime = 0x04
  16. FlagHasLastModifiedDate = 0x08
  17. FlagHasTtl = 0x10
  18. FlagHasPairs = 0x20
  19. FlagIsChunkManifest = 0x80
  20. LastModifiedBytesLength = 5
  21. TtlBytesLength = 2
  22. )
  23. func (n *Needle) DiskSize(version Version) int64 {
  24. return getActualSize(n.Size, version)
  25. }
  26. func (n *Needle) Append(w io.Writer, version Version) (size uint32, actualSize int64, err error) {
  27. if s, ok := w.(io.Seeker); ok {
  28. if end, e := s.Seek(0, 1); e == nil {
  29. defer func(s io.Seeker, off int64) {
  30. if err != nil {
  31. if _, e = s.Seek(off, 0); e != nil {
  32. glog.V(0).Infof("Failed to seek %s back to %d with error: %v", w, off, e)
  33. }
  34. }
  35. }(s, end)
  36. } else {
  37. err = fmt.Errorf("Cannot Read Current Volume Position: %v", e)
  38. return
  39. }
  40. }
  41. switch version {
  42. case Version1:
  43. header := make([]byte, NeedleEntrySize)
  44. CookieToBytes(header[0:CookieSize], n.Cookie)
  45. NeedleIdToBytes(header[CookieSize:CookieSize+NeedleIdSize], n.Id)
  46. n.Size = uint32(len(n.Data))
  47. size = n.Size
  48. util.Uint32toBytes(header[CookieSize+NeedleIdSize:CookieSize+NeedleIdSize+SizeSize], n.Size)
  49. if _, err = w.Write(header); err != nil {
  50. return
  51. }
  52. if _, err = w.Write(n.Data); err != nil {
  53. return
  54. }
  55. actualSize = NeedleEntrySize + int64(n.Size)
  56. padding := PaddingLength(n.Size, version)
  57. util.Uint32toBytes(header[0:NeedleChecksumSize], n.Checksum.Value())
  58. _, err = w.Write(header[0 : NeedleChecksumSize+padding])
  59. return
  60. case Version2, Version3:
  61. header := make([]byte, NeedleEntrySize+TimestampSize) // adding timestamp to reuse it and avoid extra allocation
  62. CookieToBytes(header[0:CookieSize], n.Cookie)
  63. NeedleIdToBytes(header[CookieSize:CookieSize+NeedleIdSize], n.Id)
  64. if len(n.Name) >= math.MaxUint8 {
  65. n.NameSize = math.MaxUint8
  66. } else {
  67. n.NameSize = uint8(len(n.Name))
  68. }
  69. n.DataSize, n.MimeSize = uint32(len(n.Data)), uint8(len(n.Mime))
  70. if n.DataSize > 0 {
  71. n.Size = 4 + n.DataSize + 1
  72. if n.HasName() {
  73. n.Size = n.Size + 1 + uint32(n.NameSize)
  74. }
  75. if n.HasMime() {
  76. n.Size = n.Size + 1 + uint32(n.MimeSize)
  77. }
  78. if n.HasLastModifiedDate() {
  79. n.Size = n.Size + LastModifiedBytesLength
  80. }
  81. if n.HasTtl() {
  82. n.Size = n.Size + TtlBytesLength
  83. }
  84. if n.HasPairs() {
  85. n.Size += 2 + uint32(n.PairsSize)
  86. }
  87. } else {
  88. n.Size = 0
  89. }
  90. size = n.DataSize
  91. util.Uint32toBytes(header[CookieSize+NeedleIdSize:CookieSize+NeedleIdSize+SizeSize], n.Size)
  92. if _, err = w.Write(header[0:NeedleEntrySize]); err != nil {
  93. return
  94. }
  95. if n.DataSize > 0 {
  96. util.Uint32toBytes(header[0:4], n.DataSize)
  97. if _, err = w.Write(header[0:4]); err != nil {
  98. return
  99. }
  100. if _, err = w.Write(n.Data); err != nil {
  101. return
  102. }
  103. util.Uint8toBytes(header[0:1], n.Flags)
  104. if _, err = w.Write(header[0:1]); err != nil {
  105. return
  106. }
  107. if n.HasName() {
  108. util.Uint8toBytes(header[0:1], n.NameSize)
  109. if _, err = w.Write(header[0:1]); err != nil {
  110. return
  111. }
  112. if _, err = w.Write(n.Name[:n.NameSize]); err != nil {
  113. return
  114. }
  115. }
  116. if n.HasMime() {
  117. util.Uint8toBytes(header[0:1], n.MimeSize)
  118. if _, err = w.Write(header[0:1]); err != nil {
  119. return
  120. }
  121. if _, err = w.Write(n.Mime); err != nil {
  122. return
  123. }
  124. }
  125. if n.HasLastModifiedDate() {
  126. util.Uint64toBytes(header[0:8], n.LastModified)
  127. if _, err = w.Write(header[8-LastModifiedBytesLength : 8]); err != nil {
  128. return
  129. }
  130. }
  131. if n.HasTtl() && n.Ttl != nil {
  132. n.Ttl.ToBytes(header[0:TtlBytesLength])
  133. if _, err = w.Write(header[0:TtlBytesLength]); err != nil {
  134. return
  135. }
  136. }
  137. if n.HasPairs() {
  138. util.Uint16toBytes(header[0:2], n.PairsSize)
  139. if _, err = w.Write(header[0:2]); err != nil {
  140. return
  141. }
  142. if _, err = w.Write(n.Pairs); err != nil {
  143. return
  144. }
  145. }
  146. }
  147. padding := PaddingLength(n.Size, version)
  148. util.Uint32toBytes(header[0:NeedleChecksumSize], n.Checksum.Value())
  149. if version == Version2 {
  150. _, err = w.Write(header[0 : NeedleChecksumSize+padding])
  151. } else {
  152. // version3
  153. util.Uint64toBytes(header[NeedleChecksumSize:NeedleChecksumSize+TimestampSize], n.AppendAtNs)
  154. _, err = w.Write(header[0 : NeedleChecksumSize+TimestampSize+padding])
  155. }
  156. return n.DataSize, getActualSize(n.Size, version), err
  157. }
  158. return 0, 0, fmt.Errorf("Unsupported Version! (%d)", version)
  159. }
  160. func ReadNeedleBlob(r *os.File, offset int64, size uint32, version Version) (dataSlice []byte, err error) {
  161. dataSlice = make([]byte, int(getActualSize(size, version)))
  162. _, err = r.ReadAt(dataSlice, offset)
  163. return dataSlice, err
  164. }
  165. func (n *Needle) ReadData(r *os.File, offset int64, size uint32, version Version) (err error) {
  166. bytes, err := ReadNeedleBlob(r, offset, size, version)
  167. if err != nil {
  168. return err
  169. }
  170. n.ParseNeedleHeader(bytes)
  171. if n.Size != size {
  172. return fmt.Errorf("File Entry Not Found. Needle id %d expected size %d Memory %d", n.Id, n.Size, size)
  173. }
  174. switch version {
  175. case Version1:
  176. n.Data = bytes[NeedleEntrySize : NeedleEntrySize+size]
  177. case Version2, Version3:
  178. n.readNeedleDataVersion2(bytes[NeedleEntrySize : NeedleEntrySize+int(n.Size)])
  179. }
  180. if size == 0 {
  181. return nil
  182. }
  183. checksum := util.BytesToUint32(bytes[NeedleEntrySize+size : NeedleEntrySize+size+NeedleChecksumSize])
  184. newChecksum := NewCRC(n.Data)
  185. if checksum != newChecksum.Value() {
  186. return errors.New("CRC error! Data On Disk Corrupted")
  187. }
  188. n.Checksum = newChecksum
  189. if version == Version3 {
  190. tsOffset := NeedleEntrySize + size + NeedleChecksumSize
  191. n.AppendAtNs = util.BytesToUint64(bytes[tsOffset : tsOffset+TimestampSize])
  192. }
  193. return nil
  194. }
  195. func (n *Needle) ParseNeedleHeader(bytes []byte) {
  196. n.Cookie = BytesToCookie(bytes[0:CookieSize])
  197. n.Id = BytesToNeedleId(bytes[CookieSize : CookieSize+NeedleIdSize])
  198. n.Size = util.BytesToUint32(bytes[CookieSize+NeedleIdSize : NeedleEntrySize])
  199. }
  200. func (n *Needle) readNeedleDataVersion2(bytes []byte) {
  201. index, lenBytes := 0, len(bytes)
  202. if index < lenBytes {
  203. n.DataSize = util.BytesToUint32(bytes[index : index+4])
  204. index = index + 4
  205. if int(n.DataSize)+index > lenBytes {
  206. // this if clause is due to bug #87 and #93, fixed in v0.69
  207. // remove this clause later
  208. return
  209. }
  210. n.Data = bytes[index : index+int(n.DataSize)]
  211. index = index + int(n.DataSize)
  212. n.Flags = bytes[index]
  213. index = index + 1
  214. }
  215. if index < lenBytes && n.HasName() {
  216. n.NameSize = uint8(bytes[index])
  217. index = index + 1
  218. n.Name = bytes[index : index+int(n.NameSize)]
  219. index = index + int(n.NameSize)
  220. }
  221. if index < lenBytes && n.HasMime() {
  222. n.MimeSize = uint8(bytes[index])
  223. index = index + 1
  224. n.Mime = bytes[index : index+int(n.MimeSize)]
  225. index = index + int(n.MimeSize)
  226. }
  227. if index < lenBytes && n.HasLastModifiedDate() {
  228. n.LastModified = util.BytesToUint64(bytes[index : index+LastModifiedBytesLength])
  229. index = index + LastModifiedBytesLength
  230. }
  231. if index < lenBytes && n.HasTtl() {
  232. n.Ttl = LoadTTLFromBytes(bytes[index : index+TtlBytesLength])
  233. index = index + TtlBytesLength
  234. }
  235. if index < lenBytes && n.HasPairs() {
  236. n.PairsSize = util.BytesToUint16(bytes[index : index+2])
  237. index += 2
  238. end := index + int(n.PairsSize)
  239. n.Pairs = bytes[index:end]
  240. index = end
  241. }
  242. }
  243. func ReadNeedleHeader(r *os.File, version Version, offset int64) (n *Needle, bodyLength int64, err error) {
  244. n = new(Needle)
  245. if version == Version1 || version == Version2 || version == Version3 {
  246. bytes := make([]byte, NeedleEntrySize)
  247. var count int
  248. count, err = r.ReadAt(bytes, offset)
  249. if count <= 0 || err != nil {
  250. return nil, 0, err
  251. }
  252. n.ParseNeedleHeader(bytes)
  253. bodyLength = NeedleBodyLength(n.Size, version)
  254. }
  255. return
  256. }
  257. func PaddingLength(needleSize uint32, version Version) uint32 {
  258. if version == Version3 {
  259. // this is same value as version2, but just listed here for clarity
  260. return NeedlePaddingSize - ((NeedleEntrySize + needleSize + NeedleChecksumSize + TimestampSize) % NeedlePaddingSize)
  261. }
  262. return NeedlePaddingSize - ((NeedleEntrySize + needleSize + NeedleChecksumSize) % NeedlePaddingSize)
  263. }
  264. func NeedleBodyLength(needleSize uint32, version Version) int64 {
  265. if version == Version3 {
  266. return int64(needleSize) + NeedleChecksumSize + TimestampSize + int64(PaddingLength(needleSize, version))
  267. }
  268. return int64(needleSize) + NeedleChecksumSize + int64(PaddingLength(needleSize, version))
  269. }
  270. //n should be a needle already read the header
  271. //the input stream will read until next file entry
  272. func (n *Needle) ReadNeedleBody(r *os.File, version Version, offset int64, bodyLength int64) (err error) {
  273. if bodyLength <= 0 {
  274. return nil
  275. }
  276. switch version {
  277. case Version1:
  278. bytes := make([]byte, bodyLength)
  279. if _, err = r.ReadAt(bytes, offset); err != nil {
  280. return
  281. }
  282. n.Data = bytes[:n.Size]
  283. n.Checksum = NewCRC(n.Data)
  284. case Version2, Version3:
  285. bytes := make([]byte, bodyLength)
  286. if _, err = r.ReadAt(bytes, offset); err != nil {
  287. return
  288. }
  289. n.readNeedleDataVersion2(bytes[0:n.Size])
  290. n.Checksum = NewCRC(n.Data)
  291. default:
  292. err = fmt.Errorf("Unsupported Version! (%d)", version)
  293. }
  294. return
  295. }
  296. func (n *Needle) IsGzipped() bool {
  297. return n.Flags&FlagGzip > 0
  298. }
  299. func (n *Needle) SetGzipped() {
  300. n.Flags = n.Flags | FlagGzip
  301. }
  302. func (n *Needle) HasName() bool {
  303. return n.Flags&FlagHasName > 0
  304. }
  305. func (n *Needle) SetHasName() {
  306. n.Flags = n.Flags | FlagHasName
  307. }
  308. func (n *Needle) HasMime() bool {
  309. return n.Flags&FlagHasMime > 0
  310. }
  311. func (n *Needle) SetHasMime() {
  312. n.Flags = n.Flags | FlagHasMime
  313. }
  314. func (n *Needle) HasLastModifiedDate() bool {
  315. return n.Flags&FlagHasLastModifiedDate > 0
  316. }
  317. func (n *Needle) SetHasLastModifiedDate() {
  318. n.Flags = n.Flags | FlagHasLastModifiedDate
  319. }
  320. func (n *Needle) HasTtl() bool {
  321. return n.Flags&FlagHasTtl > 0
  322. }
  323. func (n *Needle) SetHasTtl() {
  324. n.Flags = n.Flags | FlagHasTtl
  325. }
  326. func (n *Needle) IsChunkedManifest() bool {
  327. return n.Flags&FlagIsChunkManifest > 0
  328. }
  329. func (n *Needle) SetIsChunkManifest() {
  330. n.Flags = n.Flags | FlagIsChunkManifest
  331. }
  332. func (n *Needle) HasPairs() bool {
  333. return n.Flags&FlagHasPairs != 0
  334. }
  335. func (n *Needle) SetHasPairs() {
  336. n.Flags = n.Flags | FlagHasPairs
  337. }