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  }