github.com/scottcagno/storage@v1.8.0/pkg/lsmtree/sstable-util.go (about) 1 package lsmtree 2 3 import ( 4 "bytes" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strconv" 9 "strings" 10 ) 11 12 const ( 13 filePrefix = "sst-" 14 dataFileSuffix = ".dat" 15 indexFileSuffix = ".idx" 16 ) 17 18 func levelToDir(level int) string { 19 return fmt.Sprintf("level-%d", level) 20 } 21 22 func dirToLevel(dir string) (int, error) { 23 return strconv.Atoi(strings.Split(dir, "-")[1]) 24 } 25 26 func toDataFileName(index int64) string { 27 hexa := strconv.FormatInt(index, 16) 28 return fmt.Sprintf("%s%010s%s", filePrefix, hexa, dataFileSuffix) 29 } 30 31 func toIndexFileName(index int64) string { 32 hexa := strconv.FormatInt(index, 16) 33 return fmt.Sprintf("%s%010s%s", filePrefix, hexa, indexFileSuffix) 34 } 35 36 func fromDataFileName(name string) (int64, error) { 37 name = filepath.Base(name) 38 hexa := name[len(filePrefix) : len(name)-len(dataFileSuffix)] 39 return strconv.ParseInt(hexa, 16, 32) 40 } 41 42 func fromIndexFileName(name string) (int64, error) { 43 name = filepath.Base(name) 44 hexa := name[len(filePrefix) : len(name)-len(indexFileSuffix)] 45 return strconv.ParseInt(hexa, 16, 32) 46 } 47 48 // openDataFile opens the ss-table data file (read only) 49 func openDataFile(path string, seq int64, flag int) (*os.File, error) { 50 // get data file name 51 dataFileName := filepath.Join(path, toDataFileName(seq)) 52 // open data file 53 dataFile, err := os.OpenFile(dataFileName, os.O_RDONLY, 0666) 54 if err != nil { 55 return nil, err 56 } 57 58 // remember to close 59 //defer func(dataFile *os.File) { 60 // err := dataFile.Close() 61 // if err != nil { 62 // panic("closing dataFile: " + err.Error()) 63 // } 64 //}(dataFile) 65 66 // return data file 67 return dataFile, nil 68 } 69 70 // openIndexFile opens the ss-table index file (read only) 71 func openIndexFile(path string, seq int64, flag int) (*os.File, error) { 72 // get index file name 73 indexFileName := filepath.Join(path, toIndexFileName(seq)) 74 // open index file 75 indexFile, err := os.OpenFile(indexFileName, os.O_RDONLY, 0666) 76 if err != nil { 77 return nil, err 78 } 79 80 // remember to close 81 //defer func(indexFile *os.File) { 82 // err := indexFile.Close() 83 // if err != nil { 84 // panic("closing indexFile: " + err.Error()) 85 // } 86 //}(indexFile) 87 88 // return index file 89 return indexFile, nil 90 } 91 92 func compactSSTable(path string) error { 93 // TODO: implement me... 94 // lock and defer unlock 95 // open and load ss-table 96 // make new ss-table 97 // iterate old ss-table and write entries to new ss-table (not adding tombstone entries to batch) 98 // flush new ss-table 99 // close both ss-tables 100 // remove old ss-table (and index) 101 return nil 102 } 103 104 func mergeSSTables(sstA, sstB *ssTable, batch *Batch) error { 105 106 i, j := 0, 0 107 n1, n2 := sstA.index.Len(), sstB.index.Len() 108 109 var err error 110 var de *Entry 111 for i < n1 && j < n2 { 112 if bytes.Compare(sstA.index.data[i].Key, sstB.index.data[j].Key) == 0 { 113 // read entry from sstB 114 de, err = sstB.ReadAt(sstB.index.data[j].Offset) 115 if err != nil { 116 return err 117 } 118 // write entry to batch 119 err = batch.writeEntry(de) 120 if err != nil { 121 return err 122 } 123 i++ 124 j++ 125 continue 126 } 127 if bytes.Compare(sstA.index.data[i].Key, sstB.index.data[j].Key) == -1 { 128 // read entry from sstA 129 de, err = sstA.ReadAt(sstA.index.data[i].Offset) 130 if err != nil { 131 return err 132 } 133 // write entry to batch 134 err = batch.writeEntry(de) 135 if err != nil { 136 return err 137 } 138 i++ 139 continue 140 } 141 if bytes.Compare(sstB.index.data[j].Key, sstA.index.data[i].Key) == -1 { 142 // read entry from sstB 143 de, err = sstB.ReadAt(sstB.index.data[j].Offset) 144 if err != nil { 145 return err 146 } 147 // write entry to batch 148 err = batch.writeEntry(de) 149 if err != nil { 150 return err 151 } 152 j++ 153 continue 154 } 155 } 156 157 // print remaining 158 for i < n1 { 159 // read entry from sstA 160 de, err = sstA.ReadAt(sstA.index.data[i].Offset) 161 if err != nil { 162 return err 163 } 164 // write entry to batch 165 err = batch.writeEntry(de) 166 if err != nil { 167 return err 168 } 169 i++ 170 } 171 172 // print remaining 173 for j < n2 { 174 // read entry from sstB 175 de, err = sstB.ReadAt(sstB.index.data[j].Offset) 176 if err != nil { 177 return err 178 } 179 // write entry to batch 180 err = batch.writeEntry(de) 181 if err != nil { 182 return err 183 } 184 j++ 185 } 186 187 // return error free 188 return nil 189 }