github.com/TeaOSLab/EdgeNode@v1.3.8/internal/caches/list_file_kv.go (about)

     1  // Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
     2  
     3  package caches
     4  
     5  import (
     6  	"fmt"
     7  	"github.com/TeaOSLab/EdgeNode/internal/goman"
     8  	"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
     9  	"github.com/TeaOSLab/EdgeNode/internal/utils/fnv"
    10  	"github.com/iwind/TeaGo/types"
    11  	"strings"
    12  	"testing"
    13  )
    14  
    15  const countKVStores = 10
    16  
    17  type KVFileList struct {
    18  	dir    string
    19  	stores [countKVStores]*KVListFileStore
    20  
    21  	onAdd    func(item *Item)
    22  	onRemove func(item *Item)
    23  }
    24  
    25  func NewKVFileList(dir string) *KVFileList {
    26  	dir = strings.TrimSuffix(dir, "/")
    27  
    28  	var stores = [countKVStores]*KVListFileStore{}
    29  	for i := 0; i < countKVStores; i++ {
    30  		stores[i] = NewKVListFileStore(dir + "/db-" + types.String(i) + ".store")
    31  	}
    32  
    33  	return &KVFileList{
    34  		dir:    dir,
    35  		stores: stores,
    36  	}
    37  }
    38  
    39  // Init 初始化
    40  func (this *KVFileList) Init() error {
    41  	remotelogs.Println("CACHE", "loading database from '"+this.dir+"' ...")
    42  
    43  	var group = goman.NewTaskGroup()
    44  	var lastErr error
    45  
    46  	for _, store := range this.stores {
    47  		var storeCopy = store
    48  		group.Run(func() {
    49  			err := storeCopy.Open()
    50  			if err != nil {
    51  				lastErr = fmt.Errorf("open store '"+storeCopy.Path()+"' failed: %w", err)
    52  			}
    53  		})
    54  	}
    55  	group.Wait()
    56  
    57  	return lastErr
    58  }
    59  
    60  // Reset 重置数据
    61  func (this *KVFileList) Reset() error {
    62  	// do nothing
    63  	return nil
    64  }
    65  
    66  // Add 添加内容
    67  func (this *KVFileList) Add(hash string, item *Item) error {
    68  	err := this.getStore(hash).AddItem(hash, item)
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	if this.onAdd != nil {
    74  		this.onAdd(item)
    75  	}
    76  
    77  	return nil
    78  }
    79  
    80  // Exist 检查内容是否存在
    81  func (this *KVFileList) Exist(hash string) (bool, int64, error) {
    82  	return this.getStore(hash).ExistItem(hash)
    83  }
    84  
    85  // ExistQuick 快速检查内容是否存在
    86  func (this *KVFileList) ExistQuick(hash string) (bool, error) {
    87  	return this.getStore(hash).ExistQuickItem(hash)
    88  }
    89  
    90  // CleanPrefix 清除某个前缀的缓存
    91  func (this *KVFileList) CleanPrefix(prefix string) error {
    92  	var group = goman.NewTaskGroup()
    93  	var lastErr error
    94  	for _, store := range this.stores {
    95  		var storeCopy = store
    96  		group.Run(func() {
    97  			err := storeCopy.CleanItemsWithPrefix(prefix)
    98  			if err != nil {
    99  				lastErr = err
   100  			}
   101  		})
   102  	}
   103  	group.Wait()
   104  	return lastErr
   105  }
   106  
   107  // CleanMatchKey 清除通配符匹配的Key
   108  func (this *KVFileList) CleanMatchKey(key string) error {
   109  	var group = goman.NewTaskGroup()
   110  	var lastErr error
   111  	for _, store := range this.stores {
   112  		var storeCopy = store
   113  		group.Run(func() {
   114  			err := storeCopy.CleanItemsWithWildcardKey(key)
   115  			if err != nil {
   116  				lastErr = err
   117  			}
   118  		})
   119  	}
   120  	group.Wait()
   121  	return lastErr
   122  }
   123  
   124  // CleanMatchPrefix 清除通配符匹配的前缀
   125  func (this *KVFileList) CleanMatchPrefix(prefix string) error {
   126  	var group = goman.NewTaskGroup()
   127  	var lastErr error
   128  	for _, store := range this.stores {
   129  		var storeCopy = store
   130  		group.Run(func() {
   131  			err := storeCopy.CleanItemsWithWildcardPrefix(prefix)
   132  			if err != nil {
   133  				lastErr = err
   134  			}
   135  		})
   136  	}
   137  	group.Wait()
   138  	return lastErr
   139  }
   140  
   141  // Remove 删除内容
   142  func (this *KVFileList) Remove(hash string) error {
   143  	err := this.getStore(hash).RemoveItem(hash)
   144  	if err != nil {
   145  		return err
   146  	}
   147  
   148  	if this.onRemove != nil {
   149  		// when remove file item, no any extra information needed
   150  		this.onRemove(nil)
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  // Purge 清理过期数据
   157  func (this *KVFileList) Purge(count int, callback func(hash string) error) (int, error) {
   158  	count /= countKVStores
   159  	if count <= 0 {
   160  		count = 100
   161  	}
   162  
   163  	var countFound = 0
   164  	var lastErr error
   165  	for _, store := range this.stores {
   166  		purgeCount, err := store.PurgeItems(count, callback)
   167  		countFound += purgeCount
   168  		if err != nil {
   169  			lastErr = err
   170  		}
   171  	}
   172  
   173  	return countFound, lastErr
   174  }
   175  
   176  // PurgeLFU 清理LFU数据
   177  func (this *KVFileList) PurgeLFU(count int, callback func(hash string) error) error {
   178  	count /= countKVStores
   179  	if count <= 0 {
   180  		count = 100
   181  	}
   182  
   183  	var lastErr error
   184  	for _, store := range this.stores {
   185  		err := store.PurgeLFUItems(count, callback)
   186  		if err != nil {
   187  			lastErr = err
   188  		}
   189  	}
   190  	return lastErr
   191  }
   192  
   193  // CleanAll 清除所有缓存
   194  func (this *KVFileList) CleanAll() error {
   195  	var group = goman.NewTaskGroup()
   196  	var lastErr error
   197  	for _, store := range this.stores {
   198  		var storeCopy = store
   199  		group.Run(func() {
   200  			err := storeCopy.RemoveAllItems()
   201  			if err != nil {
   202  				lastErr = err
   203  			}
   204  		})
   205  	}
   206  	group.Wait()
   207  	return lastErr
   208  }
   209  
   210  // Stat 统计
   211  func (this *KVFileList) Stat(check func(hash string) bool) (*Stat, error) {
   212  	var stat = &Stat{}
   213  
   214  	var group = goman.NewTaskGroup()
   215  
   216  	var lastErr error
   217  	for _, store := range this.stores {
   218  		var storeCopy = store
   219  		group.Run(func() {
   220  			storeStat, err := storeCopy.StatItems()
   221  			if err != nil {
   222  				lastErr = err
   223  				return
   224  			}
   225  
   226  			group.Lock()
   227  			stat.Size += storeStat.Size
   228  			stat.ValueSize += storeStat.ValueSize
   229  			stat.Count += storeStat.Count
   230  			group.Unlock()
   231  		})
   232  	}
   233  
   234  	group.Wait()
   235  
   236  	return stat, lastErr
   237  }
   238  
   239  // Count 总数量
   240  func (this *KVFileList) Count() (int64, error) {
   241  	var count int64
   242  
   243  	var group = goman.NewTaskGroup()
   244  
   245  	var lastErr error
   246  	for _, store := range this.stores {
   247  		var storeCopy = store
   248  		group.Run(func() {
   249  			countStoreItems, err := storeCopy.CountItems()
   250  			if err != nil {
   251  				lastErr = err
   252  				return
   253  			}
   254  
   255  			group.Lock()
   256  			count += countStoreItems
   257  			group.Unlock()
   258  		})
   259  	}
   260  
   261  	group.Wait()
   262  
   263  	return count, lastErr
   264  }
   265  
   266  // OnAdd 添加事件
   267  func (this *KVFileList) OnAdd(fn func(item *Item)) {
   268  	this.onAdd = fn
   269  }
   270  
   271  // OnRemove 删除事件
   272  func (this *KVFileList) OnRemove(fn func(item *Item)) {
   273  	this.onRemove = fn
   274  }
   275  
   276  // Close 关闭
   277  func (this *KVFileList) Close() error {
   278  	var lastErr error
   279  	var group = goman.NewTaskGroup()
   280  	for _, store := range this.stores {
   281  		var storeCopy = store
   282  		group.Run(func() {
   283  			err := storeCopy.Close()
   284  			if err != nil {
   285  				lastErr = err
   286  			}
   287  		})
   288  	}
   289  	group.Wait()
   290  	return lastErr
   291  }
   292  
   293  // IncreaseHit 增加点击量
   294  func (this *KVFileList) IncreaseHit(hash string) error {
   295  	// do nothing
   296  	return nil
   297  }
   298  
   299  func (this *KVFileList) TestInspect(t *testing.T) error {
   300  	for _, store := range this.stores {
   301  		err := store.TestInspect(t)
   302  		if err != nil {
   303  			return err
   304  		}
   305  	}
   306  	return nil
   307  }
   308  
   309  func (this *KVFileList) getStore(hash string) *KVListFileStore {
   310  	return this.stores[fnv.HashString(hash)%countKVStores]
   311  }