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.

111 lines
2.9 KiB

  1. package storage
  2. import (
  3. "code.google.com/p/weed-fs/go/util"
  4. "fmt"
  5. "io"
  6. "os"
  7. )
  8. type NeedleMap struct {
  9. indexFile *os.File
  10. m CompactMap
  11. //transient
  12. bytes []byte
  13. deletionCounter int
  14. fileCounter int
  15. deletionByteCounter uint64
  16. fileByteCounter uint64
  17. }
  18. func NewNeedleMap(file *os.File) *NeedleMap {
  19. nm := &NeedleMap{
  20. m: NewCompactMap(),
  21. bytes: make([]byte, 16),
  22. indexFile: file,
  23. }
  24. return nm
  25. }
  26. const (
  27. RowsToRead = 1024
  28. )
  29. func LoadNeedleMap(file *os.File) (*NeedleMap, error) {
  30. nm := NewNeedleMap(file)
  31. bytes := make([]byte, 16*RowsToRead)
  32. count, e := nm.indexFile.Read(bytes)
  33. for count > 0 && e == nil {
  34. for i := 0; i < count; i += 16 {
  35. key := util.BytesToUint64(bytes[i : i+8])
  36. offset := util.BytesToUint32(bytes[i+8 : i+12])
  37. size := util.BytesToUint32(bytes[i+12 : i+16])
  38. nm.fileCounter++
  39. nm.fileByteCounter = nm.fileByteCounter + uint64(size)
  40. if offset > 0 {
  41. oldSize := nm.m.Set(Key(key), offset, size)
  42. //log.Println("reading key", key, "offset", offset, "size", size, "oldSize", oldSize)
  43. if oldSize > 0 {
  44. nm.deletionCounter++
  45. nm.deletionByteCounter = nm.deletionByteCounter + uint64(oldSize)
  46. }
  47. } else {
  48. oldSize := nm.m.Delete(Key(key))
  49. //log.Println("removing key", key, "offset", offset, "size", size, "oldSize", oldSize)
  50. nm.deletionCounter++
  51. nm.deletionByteCounter = nm.deletionByteCounter + uint64(oldSize)
  52. }
  53. }
  54. count, e = nm.indexFile.Read(bytes)
  55. }
  56. if e == io.EOF {
  57. e = nil
  58. }
  59. return nm, e
  60. }
  61. func (nm *NeedleMap) Put(key uint64, offset uint32, size uint32) (int, error) {
  62. oldSize := nm.m.Set(Key(key), offset, size)
  63. util.Uint64toBytes(nm.bytes[0:8], key)
  64. util.Uint32toBytes(nm.bytes[8:12], offset)
  65. util.Uint32toBytes(nm.bytes[12:16], size)
  66. nm.fileCounter++
  67. nm.fileByteCounter = nm.fileByteCounter + uint64(size)
  68. if oldSize > 0 {
  69. nm.deletionCounter++
  70. nm.deletionByteCounter = nm.deletionByteCounter + uint64(oldSize)
  71. }
  72. return nm.indexFile.Write(nm.bytes)
  73. }
  74. func (nm *NeedleMap) Get(key uint64) (element *NeedleValue, ok bool) {
  75. element, ok = nm.m.Get(Key(key))
  76. return
  77. }
  78. func (nm *NeedleMap) Delete(key uint64) error {
  79. nm.deletionByteCounter = nm.deletionByteCounter + uint64(nm.m.Delete(Key(key)))
  80. offset, err := nm.indexFile.Seek(0, 1)
  81. if err != nil {
  82. return fmt.Errorf("cannot get position of indexfile: %s", err)
  83. }
  84. util.Uint64toBytes(nm.bytes[0:8], key)
  85. util.Uint32toBytes(nm.bytes[8:12], 0)
  86. util.Uint32toBytes(nm.bytes[12:16], 0)
  87. if _, err = nm.indexFile.Write(nm.bytes); err != nil {
  88. nm.indexFile.Truncate(offset)
  89. return fmt.Errorf("error writing to indexfile %s: %s", nm.indexFile, err)
  90. }
  91. nm.deletionCounter++
  92. return nil
  93. }
  94. func (nm *NeedleMap) Close() {
  95. nm.indexFile.Close()
  96. }
  97. func (nm *NeedleMap) ContentSize() uint64 {
  98. return nm.fileByteCounter
  99. }
  100. func (nm *NeedleMap) Visit(visit func(NeedleValue) error) (err error) {
  101. return nm.m.Visit(visit)
  102. }