github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/blob/local/localstorage.go (about) 1 /* 2 Copyright 2023. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package local 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "io" 23 "os" 24 "path" 25 "strings" 26 "sync" 27 "time" 28 29 "github.com/siglens/siglens/pkg/blob/ssutils" 30 "github.com/siglens/siglens/pkg/config" 31 "github.com/siglens/siglens/pkg/segment/structs" 32 log "github.com/sirupsen/logrus" 33 ) 34 35 var segSetKeys = map[string]*structs.SegSetData{} 36 var segSetKeysLock *sync.Mutex = &sync.Mutex{} 37 var segSetKeysFileName = "ssd.json" 38 39 func InitLocalStorage() error { 40 segSetKeysLock.Lock() 41 defer segSetKeysLock.Unlock() 42 filePath := config.GetDataPath() + "common/" + segSetKeysFileName 43 file, err := os.ReadFile(filePath) 44 if err != nil { 45 if !os.IsNotExist(err) { 46 log.Errorf("InitLocalStorage: Error reading SegSetKeys file %s: %v", filePath, err) 47 return err 48 } 49 } else { 50 if err := json.Unmarshal(file, &segSetKeys); err != nil { 51 log.Errorf("InitLocalStorage: Error unmarshalling SegSetKeys file %s: %v", filePath, err) 52 return err 53 } 54 } 55 56 // only if s3 is enabled & we are uploading to s3 should we start up the cleaner 57 if config.IsS3Enabled() { 58 initLocalCleaner() 59 } 60 go persistSegSetKeysOnInterval() 61 return nil 62 } 63 64 func persistSegSetKeysOnInterval() { 65 for { 66 time.Sleep(1 * time.Minute) 67 ForceFlushSegSetKeysToFile() 68 } 69 } 70 71 func ForceFlushSegSetKeysToFile() { 72 segSetKeysLock.Lock() 73 defer segSetKeysLock.Unlock() 74 75 // write Segsetkeys to ssd.json 76 filePath := config.GetDataPath() + "common/" + segSetKeysFileName 77 fd, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) 78 if err != nil { 79 log.Errorf("ForceFlushSegSetKeysToFile: Error creating file %s: %v", filePath, err) 80 return 81 } 82 defer fd.Close() 83 segSetKeysJson, err := json.Marshal(&segSetKeys) 84 if err != nil { 85 log.Errorf("ForceFlushSegSetKeysToFile: Error marshalling SegSetKeys: %v", err) 86 return 87 } 88 if _, err := fd.Write(segSetKeysJson); err != nil { 89 log.Errorf("ForceFlushSegSetKeysToFile: Error writing to file %s: %v", filePath, err) 90 return 91 } 92 } 93 94 /* 95 Adds []string to metadata of on disk files 96 97 This assumes that segSetFile has been properly initialized with latest and size 98 */ 99 func BulkAddSegSetFilesToLocal(segSetFiles []string) { 100 for _, sfile := range segSetFiles { 101 if sfile == "" { 102 continue 103 } 104 size, ok := ssutils.GetFileSizeFromDisk(sfile) 105 if !ok { 106 log.Errorf("BulkAddSegSetFilesToLocal: GetFileSizeFromDisk %+v does not exist in localstorage", sfile) 107 } 108 ssData := ssutils.NewSegSetData(sfile, size) 109 AddSegSetFileToLocal(sfile, ssData) 110 } 111 } 112 113 /* 114 Adds a single table and segsetFile to the local storage 115 116 # Internally, also adds the file information to the heap 117 118 This assumes that segSetData has been properly initialized with latest and size 119 */ 120 func AddSegSetFileToLocal(fName string, segSetData *structs.SegSetData) { 121 segSetKeysLock.Lock() 122 defer segSetKeysLock.Unlock() 123 124 if strings.Contains(fName, "/active/") { 125 return 126 } 127 if _, exists := segSetKeys[fName]; !exists { 128 segSetKeys[fName] = segSetData 129 allSortedSegSetFiles.Push(segSetData) 130 } 131 segSetKeys[fName].AccessTime = time.Now().Unix() 132 } 133 134 /* 135 Sets SegSetData.InUse = true for the input segSetFile 136 137 Returns an error if SetSetData does not exist in SegSetKeys 138 */ 139 140 func SetBlobAsInUse(fName string) error { 141 142 segSetKeysLock.Lock() 143 defer segSetKeysLock.Unlock() 144 145 if strings.Contains(fName, "/active/") { 146 return nil 147 } 148 if _, exists := segSetKeys[fName]; exists { 149 segSetKeys[fName].AccessTime = time.Now().Unix() 150 segSetKeys[fName].InUse = true 151 return nil 152 153 } 154 return fmt.Errorf("tried to mark segSetFile: %+v as in use that does not exist in localstorage", 155 fName) 156 } 157 158 /* 159 Returns if the file exists in the local SegSetKeys struct 160 */ 161 func IsFilePresentOnLocal(fName string) bool { 162 segSetKeysLock.Lock() 163 defer segSetKeysLock.Unlock() 164 if _, exists := segSetKeys[fName]; exists { 165 segSetKeys[fName].AccessTime = time.Now().Unix() 166 return true 167 } 168 return false 169 } 170 171 func DeleteLocal(fName string) error { 172 segSetKeysLock.Lock() 173 defer segSetKeysLock.Unlock() 174 if strings.Contains(fName, "/active/") { 175 log.Debugf("Not deleting segset from active dir %v", fName) 176 delete(segSetKeys, fName) 177 return fmt.Errorf("not deleting segset from active dir %v", fName) 178 } 179 if _, exists := segSetKeys[fName]; exists && fName != "" { 180 deleteLocalFile(fName) 181 delete(segSetKeys, fName) 182 log.Debugf("DeleteSegSetFileFromSegSetKey %v ", fName) 183 return nil 184 } 185 return nil 186 } 187 188 func deleteLocalFile(file string) { 189 if err := os.Remove(file); err != nil { 190 log.Errorf("ssregistry.local: deleteLocalFile: Error deleting file %s: %v", file, err) 191 } 192 193 recursivelyDeleteParentDirectories(file) 194 } 195 196 func recursivelyDeleteParentDirectories(filePath string) { 197 temp := path.Dir(filePath) 198 for { 199 if temp == config.GetDataPath() { 200 break 201 } 202 if isDirEmpty(temp) { 203 os.RemoveAll(temp) 204 } else { 205 break 206 } 207 temp = path.Dir(temp) 208 } 209 } 210 211 func isDirEmpty(name string) bool { 212 f, err := os.Open(name) 213 if err != nil { 214 return false 215 } 216 defer f.Close() 217 218 _, err = f.Readdir(1) 219 return err == io.EOF 220 } 221 222 /* 223 Returns the local file size and a bool indicating if the file existed 224 Internally, updates access time of local file 225 */ 226 func GetLocalFileSize(segSetFile string) (uint64, bool) { 227 228 segSetKeysLock.Lock() 229 defer segSetKeysLock.Unlock() 230 if _, exists := segSetKeys[segSetFile]; exists { 231 segSetKeys[segSetFile].AccessTime = time.Now().Unix() 232 return segSetKeys[segSetFile].Size, true 233 } 234 return 0, false 235 } 236 237 /* 238 Sets SegSetData.InUse = false for the input segSetFile 239 Returns an error if SetSetData does not exist in SegSetKeys 240 */ 241 func SetBlobAsNotInUse(segSetFile string) error { 242 segSetKeysLock.Lock() 243 defer segSetKeysLock.Unlock() 244 if strings.Contains(segSetFile, "/active/") { 245 return nil 246 } 247 if _, exists := segSetKeys[segSetFile]; exists { 248 segSetKeys[segSetFile].AccessTime = time.Now().Unix() 249 segSetKeys[segSetFile].InUse = false 250 return nil 251 252 } 253 return fmt.Errorf("tried to mark segSetFile: %+v as not use that does not exist in localstorage", 254 segSetFile) 255 }