github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/internal/cache/entry.go (about)

     1  // Copyright 2020 The LevelDB-Go and Pebble Authors. All rights reserved. Use
     2  // of this source code is governed by a BSD-style license that can be found in
     3  // the LICENSE file.
     4  
     5  package cache
     6  
     7  type entryType int8
     8  
     9  const (
    10  	etTest entryType = iota
    11  	etCold
    12  	etHot
    13  )
    14  
    15  func (p entryType) String() string {
    16  	switch p {
    17  	case etTest:
    18  		return "test"
    19  	case etCold:
    20  		return "cold"
    21  	case etHot:
    22  		return "hot"
    23  	}
    24  	return "unknown"
    25  }
    26  
    27  // entry holds the metadata for a cache entry. The memory for an entry is
    28  // allocated from manually managed memory.
    29  //
    30  // Using manual memory management for entries is technically a volation of the
    31  // Cgo pointer rules:
    32  //
    33  //	https://golang.org/cmd/cgo/#hdr-Passing_pointers
    34  //
    35  // Specifically, Go pointers should not be stored in C allocated memory. The
    36  // reason for this rule is that the Go GC will not look at C allocated memory
    37  // to find pointers to Go objects. If the only reference to a Go object is
    38  // stored in C allocated memory, the object will be reclaimed. The shard field
    39  // of the entry struct points to a Go allocated object, thus the
    40  // violation. What makes this "safe" is that the Cache guarantees that there
    41  // are other pointers to the shard which will keep it alive.
    42  type entry struct {
    43  	key key
    44  	// The value associated with the entry. The entry holds a reference on the
    45  	// value which is maintained by entry.setValue().
    46  	val       *Value
    47  	blockLink struct {
    48  		next *entry
    49  		prev *entry
    50  	}
    51  	fileLink struct {
    52  		next *entry
    53  		prev *entry
    54  	}
    55  	size  int64
    56  	ptype entryType
    57  	// referenced is atomically set to indicate that this entry has been accessed
    58  	// since the last time one of the clock hands swept it.
    59  	referenced int32
    60  	shard      *shard
    61  	// Reference count for the entry. The entry is freed when the reference count
    62  	// drops to zero.
    63  	ref refcnt
    64  }
    65  
    66  func newEntry(s *shard, key key, size int64) *entry {
    67  	e := entryAllocNew()
    68  	*e = entry{
    69  		key:   key,
    70  		size:  size,
    71  		ptype: etCold,
    72  		shard: s,
    73  	}
    74  	e.blockLink.next = e
    75  	e.blockLink.prev = e
    76  	e.fileLink.next = e
    77  	e.fileLink.prev = e
    78  	e.ref.init(1)
    79  	return e
    80  }
    81  
    82  func (e *entry) free() {
    83  	e.setValue(nil)
    84  	*e = entry{}
    85  	entryAllocFree(e)
    86  }
    87  
    88  func (e *entry) next() *entry {
    89  	if e == nil {
    90  		return nil
    91  	}
    92  	return e.blockLink.next
    93  }
    94  
    95  func (e *entry) prev() *entry {
    96  	if e == nil {
    97  		return nil
    98  	}
    99  	return e.blockLink.prev
   100  }
   101  
   102  func (e *entry) link(s *entry) {
   103  	s.blockLink.prev = e.blockLink.prev
   104  	s.blockLink.prev.blockLink.next = s
   105  	s.blockLink.next = e
   106  	s.blockLink.next.blockLink.prev = s
   107  }
   108  
   109  func (e *entry) unlink() *entry {
   110  	next := e.blockLink.next
   111  	e.blockLink.prev.blockLink.next = e.blockLink.next
   112  	e.blockLink.next.blockLink.prev = e.blockLink.prev
   113  	e.blockLink.prev = e
   114  	e.blockLink.next = e
   115  	return next
   116  }
   117  
   118  func (e *entry) linkFile(s *entry) {
   119  	s.fileLink.prev = e.fileLink.prev
   120  	s.fileLink.prev.fileLink.next = s
   121  	s.fileLink.next = e
   122  	s.fileLink.next.fileLink.prev = s
   123  }
   124  
   125  func (e *entry) unlinkFile() *entry {
   126  	next := e.fileLink.next
   127  	e.fileLink.prev.fileLink.next = e.fileLink.next
   128  	e.fileLink.next.fileLink.prev = e.fileLink.prev
   129  	e.fileLink.prev = e
   130  	e.fileLink.next = e
   131  	return next
   132  }
   133  
   134  func (e *entry) setValue(v *Value) {
   135  	if v != nil {
   136  		v.acquire()
   137  	}
   138  	old := e.val
   139  	e.val = v
   140  	if old != nil {
   141  		old.release()
   142  	}
   143  }
   144  
   145  func (e *entry) peekValue() *Value {
   146  	return e.val
   147  }
   148  
   149  func (e *entry) acquireValue() *Value {
   150  	v := e.val
   151  	if v != nil {
   152  		v.acquire()
   153  	}
   154  	return v
   155  }