github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/segment/writer/metrics/meta/metricsmeta.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 meta
    18  
    19  import (
    20  	"bufio"
    21  	"encoding/json"
    22  	"os"
    23  	"path"
    24  	"sync"
    25  
    26  	"github.com/siglens/siglens/pkg/common/fileutils"
    27  	"github.com/siglens/siglens/pkg/config"
    28  	"github.com/siglens/siglens/pkg/segment/structs"
    29  	log "github.com/sirupsen/logrus"
    30  )
    31  
    32  /**
    33  
    34  	This module exposes require functions to read/write/query the hosts' metricsmeta.json
    35  
    36  **/
    37  
    38  var MetricsMetaSuffix = "metricmeta.json"
    39  
    40  var mMetaLock *sync.RWMutex = &sync.RWMutex{}
    41  var localMetricsMeta string
    42  
    43  func GetLocalMetricsMetaFName() string {
    44  	return config.GetSmrBaseDir() + MetricsMetaSuffix
    45  }
    46  
    47  func InitMetricsMeta() error {
    48  	localMetricsMeta = GetLocalMetricsMetaFName()
    49  	return nil
    50  }
    51  
    52  func AddMetricsMetaEntry(entry *structs.MetricsMeta) error {
    53  	mMetaLock.Lock()
    54  	defer mMetaLock.Unlock()
    55  	fd, err := os.OpenFile(localMetricsMeta, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
    56  	if err != nil {
    57  		log.Errorf("AddMetricsMetaEntry: failed to open filename=%v: err=%v", localMetricsMeta, err)
    58  		return err
    59  	}
    60  
    61  	defer fd.Close()
    62  
    63  	rawMeta, err := json.Marshal(entry)
    64  	if err != nil {
    65  		log.Errorf("AddMetricsMetaEntry: failed to Marshal: err=%v", err)
    66  		return err
    67  	}
    68  
    69  	if _, err := fd.Write(rawMeta); err != nil {
    70  		log.Errorf("AddMetricsMetaEntry: failed to write segmeta filename=%v: err=%v", localMetricsMeta, err)
    71  		return err
    72  	}
    73  
    74  	if _, err := fd.WriteString("\n"); err != nil {
    75  		log.Errorf("AddMetricsMetaEntry: failed to write newline filename=%v: err=%v", localMetricsMeta, err)
    76  		return err
    77  	}
    78  	err = fd.Sync()
    79  	if err != nil {
    80  		log.Errorf("AddMetricsMetaEntry: failed to sync filename=%v: err=%v", localMetricsMeta, err)
    81  		return err
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  func GetLocalMetricsMetaEntries() (map[string]*structs.MetricsMeta, error) {
    88  	return ReadMetricsMeta(localMetricsMeta)
    89  }
    90  
    91  func ReadMetricsMeta(mmeta string) (map[string]*structs.MetricsMeta, error) {
    92  	mMetaLock.RLock()
    93  	defer mMetaLock.RUnlock()
    94  	fd, err := os.OpenFile(mmeta, os.O_APPEND|os.O_RDONLY|os.O_CREATE, 0644)
    95  	if err != nil {
    96  		if os.IsNotExist(err) {
    97  			return map[string]*structs.MetricsMeta{}, nil
    98  		}
    99  		log.Errorf("GetLocalMetricsMetaEntries: failed to open filename=%v: err=%v", mmeta, err)
   100  		return nil, err
   101  	}
   102  
   103  	defer fd.Close()
   104  
   105  	retVal := make(map[string]*structs.MetricsMeta)
   106  	scanner := bufio.NewScanner(fd)
   107  	for scanner.Scan() {
   108  		rawbytes := scanner.Bytes()
   109  		var mMeta structs.MetricsMeta
   110  		err := json.Unmarshal(rawbytes, &mMeta)
   111  		if err != nil {
   112  			log.Errorf("GetLocalMetricsMetaEntries: Cannot unmarshal data = %v, err= %v", string(rawbytes), err)
   113  			continue
   114  		}
   115  		retVal[mMeta.MSegmentDir] = &mMeta
   116  	}
   117  
   118  	return retVal, nil
   119  }
   120  
   121  // includes remote metrics meta entries
   122  func GetAllMetricsMetaEntries(orgid uint64) (map[string]*structs.MetricsMeta, error) {
   123  	nDir := config.GetIngestNodeBaseDir()
   124  	files, err := os.ReadDir(nDir)
   125  	if err != nil {
   126  		log.Errorf("ReadAllSegmetas: read dir err=%v ", err)
   127  		return make(map[string]*structs.MetricsMeta, 0), nil
   128  	}
   129  
   130  	// read all mmetas
   131  	iNodes := make([]string, 0)
   132  	for _, file := range files {
   133  		fName := file.Name()
   134  		iNodes = append(iNodes, fName)
   135  	}
   136  
   137  	allSegmetas := make([]string, 0)
   138  	for _, iNode := range iNodes {
   139  		mDir := path.Join(nDir, iNode, MetricsMetaSuffix)
   140  		if _, err := os.Stat(mDir); err != nil {
   141  			continue
   142  		}
   143  		allSegmetas = append(allSegmetas, mDir)
   144  	}
   145  
   146  	retVal := make(map[string]*structs.MetricsMeta)
   147  	for _, fName := range allSegmetas {
   148  		mMetas, err := ReadMetricsMeta(fName)
   149  		if err != nil {
   150  			log.Errorf("ReadAllSegmetas: read segmeta err=%v ", err)
   151  			continue
   152  		}
   153  
   154  		for k, v := range mMetas {
   155  			if v.OrgId == orgid {
   156  				retVal[k] = v
   157  			}
   158  		}
   159  	}
   160  	return retVal, nil
   161  }
   162  
   163  func RemoveMetricsSegments(mmetaName string, metricsSegmentsToDelete map[string]*structs.MetricsMeta) {
   164  	mMetaLock.Lock()
   165  	defer mMetaLock.Unlock()
   166  
   167  	removeMetricsSegmentsByList(mmetaName, metricsSegmentsToDelete)
   168  }
   169  
   170  func removeMetricsSegmentsByList(metricsMetaFile string, metricsSegmentsToDelete map[string]*structs.MetricsMeta) {
   171  
   172  	if metricsSegmentsToDelete == nil {
   173  		return
   174  	}
   175  
   176  	preservedEntries := make([]*structs.MetricsMeta, 0)
   177  	tagsTreeToDelete := make(map[string]bool)
   178  
   179  	entriesRead := 0
   180  	entriesRemoved := 0
   181  	fd, err := os.OpenFile(metricsMetaFile, os.O_RDONLY, 0644)
   182  	if err != nil {
   183  		log.Errorf("removeMetricsSegmentsByList: Failed to open metrics meta file name=%v, err:%v", metricsMetaFile, err)
   184  		return
   185  	}
   186  	defer fd.Close()
   187  
   188  	reader := bufio.NewScanner(fd)
   189  	for reader.Scan() {
   190  		metricSegmentMeta := structs.MetricsMeta{}
   191  		err = json.Unmarshal(reader.Bytes(), &metricSegmentMeta)
   192  		if err != nil {
   193  			log.Errorf("removeMetricsSegmentsByList: Failed to unmarshal metrics meta file=%v, err:%v", metricsMetaFile, err)
   194  			continue
   195  		}
   196  		entriesRead++
   197  
   198  		_, ok := metricsSegmentsToDelete[metricSegmentMeta.MSegmentDir]
   199  		if !ok {
   200  			preservedEntries = append(preservedEntries, &metricSegmentMeta)
   201  			continue
   202  		}
   203  		entriesRemoved++
   204  		dir := path.Dir(metricSegmentMeta.MSegmentDir)
   205  		if err := os.RemoveAll(dir); err != nil {
   206  			log.Errorf("removeMetricsSegmentsByList: Failed to remove directory name=%v, err:%v",
   207  				metricSegmentMeta.MSegmentDir, err)
   208  		}
   209  		fileutils.RecursivelyDeleteEmptyParentDirectories(dir)
   210  
   211  		if _, ok := tagsTreeToDelete[metricSegmentMeta.TTreeDir]; !ok {
   212  			tagsTreeToDelete[metricSegmentMeta.TTreeDir] = true
   213  		}
   214  	}
   215  	if entriesRemoved > 0 {
   216  		// if we removed entries and there was nothing preserved then we must delete this metrics meta file
   217  		if len(preservedEntries) == 0 {
   218  			if err := os.RemoveAll(metricsMetaFile); err != nil {
   219  				log.Errorf("removeMetricsSegmentsByList: Failed to remove metrics meta file name=%v, err:%v", metricsMetaFile, err)
   220  			}
   221  		} else {
   222  			wfd, err := os.OpenFile(metricsMetaFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
   223  			if err != nil {
   224  				log.Errorf("removeMetricsSegmentsByList: Failed to open temp metrics meta file name=%v, err:%v", metricsMetaFile, err)
   225  				return
   226  			}
   227  			defer wfd.Close()
   228  			for _, mentry := range preservedEntries {
   229  				// delete tags trees for removed segments
   230  				// if ttdir existed in tagsTreeToDelete, that means a preserved metrics entry still will use this ttree
   231  				delete(tagsTreeToDelete, mentry.TTreeDir)
   232  
   233  				msegjson, err := json.Marshal(*mentry)
   234  				if err != nil {
   235  					log.Errorf("removeMetricsSegmentsByList: failed to Marshal: err=%v", err)
   236  					return
   237  				}
   238  
   239  				if _, err := wfd.Write(msegjson); err != nil {
   240  					log.Errorf("removeMetricsSegmentsByList: failed to write metrics meta filename=%v: err=%v", metricsMetaFile, err)
   241  					return
   242  				}
   243  
   244  				if _, err := wfd.WriteString("\n"); err != nil {
   245  					log.Errorf("removeMetricsSegmentsByList: failed to write new line to metrics meta filename=%v: err=%v", metricsMetaFile, err)
   246  					return
   247  				}
   248  			}
   249  		}
   250  	}
   251  	for ttreeDir := range tagsTreeToDelete {
   252  		dir := path.Dir(ttreeDir)
   253  		if err := os.RemoveAll(ttreeDir); err != nil {
   254  			log.Errorf("removeMetricsSegmentsByList: Failed to remove tags tree directory=%v, err:%v", ttreeDir, err)
   255  		}
   256  		fileutils.RecursivelyDeleteEmptyParentDirectories(dir)
   257  	}
   258  }