LCOV - code coverage report
Current view: top level - pebble/internal/cache - value.go (source / functions) Hit Total Coverage
Test: 2024-11-29 08:17Z 1724e81e - meta test only.lcov Lines: 40 57 70.2 %
Date: 2024-11-29 08:18:05 Functions: 0 0 -

          Line data    Source code
       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             : import (
       8             :         "fmt"
       9             :         "os"
      10             :         "unsafe"
      11             : 
      12             :         "github.com/cockroachdb/pebble/internal/buildtags"
      13             :         "github.com/cockroachdb/pebble/internal/invariants"
      14             :         "github.com/cockroachdb/pebble/internal/manual"
      15             : )
      16             : 
      17             : // ValueMetadataSize denotes the number of bytes of metadata allocated for a
      18             : // cache entry. Note that builds with cgo disabled allocate no metadata, and
      19             : // 32-bit builds allocate less for a cache.Value. However, we keep the value
      20             : // constant to reduce friction for writing tests.
      21             : const ValueMetadataSize = 32
      22             : 
      23             : // Assert that the size of a Value{} is less than or equal to the
      24             : // ValueMetadataSize.
      25             : var _ uint = ValueMetadataSize - uint(unsafe.Sizeof(Value{}))
      26             : 
      27             : // Value holds a reference counted immutable value.
      28             : type Value struct {
      29             :         // buf is allocated using the manual package.
      30             :         buf []byte
      31             :         // Reference count for the value. The value is freed when the reference count
      32             :         // drops to zero.
      33             :         ref refcnt
      34             : }
      35             : 
      36             : // The Value struct is normally allocated together with the buffer using manual
      37             : // memory.
      38             : //
      39             : // If cgo is not available, the Value must be a normal Go object to keep
      40             : // the buffer reference visible to the GC. We also use the Go allocator if we
      41             : // want to add finalizer assertions.
      42             : const valueEntryGoAllocated = !buildtags.Cgo || invariants.UseFinalizers
      43             : 
      44           1 : func newValue(n int) *Value {
      45           1 :         if n == 0 {
      46           0 :                 return nil
      47           0 :         }
      48             : 
      49           1 :         if valueEntryGoAllocated {
      50           1 :                 // Note: if cgo is not enabled, manual.New will do a regular Go allocation.
      51           1 :                 b := manual.New(manual.BlockCacheData, n)
      52           1 :                 v := &Value{buf: b}
      53           1 :                 v.ref.init(1)
      54           1 :                 // Note: this is a no-op if invariants and tracing are disabled or race is
      55           1 :                 // enabled.
      56           1 :                 invariants.SetFinalizer(v, func(obj interface{}) {
      57           1 :                         v := obj.(*Value)
      58           1 :                         if v.buf != nil {
      59           0 :                                 fmt.Fprintf(os.Stderr, "%p: cache value was not freed: refs=%d\n%s",
      60           0 :                                         v, v.refs(), v.ref.traces())
      61           0 :                                 os.Exit(1)
      62           0 :                         }
      63             :                 })
      64           1 :                 return v
      65             :         }
      66             :         // When we're not performing leak detection, the lifetime of the returned
      67             :         // Value is exactly the lifetime of the backing buffer and we can manually
      68             :         // allocate both.
      69           0 :         b := manual.New(manual.BlockCacheData, ValueMetadataSize+n)
      70           0 :         v := (*Value)(unsafe.Pointer(&b[0]))
      71           0 :         v.buf = b[ValueMetadataSize:]
      72           0 :         v.ref.init(1)
      73           0 :         return v
      74             : }
      75             : 
      76           1 : func (v *Value) free() {
      77           1 :         if invariants.Enabled {
      78           1 :                 // Poison the contents to help catch use-after-free bugs.
      79           1 :                 for i := range v.buf {
      80           1 :                         v.buf[i] = 0xff
      81           1 :                 }
      82             :         }
      83           1 :         if valueEntryGoAllocated {
      84           1 :                 manual.Free(manual.BlockCacheData, v.buf)
      85           1 :                 v.buf = nil
      86           1 :                 return
      87           1 :         }
      88           0 :         n := ValueMetadataSize + cap(v.buf)
      89           0 :         buf := unsafe.Slice((*byte)(unsafe.Pointer(v)), n)
      90           0 :         v.buf = nil
      91           0 :         manual.Free(manual.BlockCacheData, buf)
      92             : }
      93             : 
      94             : // Buf returns the buffer associated with the value. The contents of the buffer
      95             : // should not be changed once the value has been added to the cache. Instead, a
      96             : // new Value should be created and added to the cache to replace the existing
      97             : // value.
      98           1 : func (v *Value) Buf() []byte {
      99           1 :         if v == nil {
     100           0 :                 return nil
     101           0 :         }
     102           1 :         return v.buf
     103             : }
     104             : 
     105             : // Truncate the buffer to the specified length. The buffer length should not be
     106             : // changed once the value has been added to the cache as there may be
     107             : // concurrent readers of the Value. Instead, a new Value should be created and
     108             : // added to the cache to replace the existing value.
     109           1 : func (v *Value) Truncate(n int) {
     110           1 :         v.buf = v.buf[:n]
     111           1 : }
     112             : 
     113           1 : func (v *Value) refs() int32 {
     114           1 :         return v.ref.refs()
     115           1 : }
     116             : 
     117           1 : func (v *Value) acquire() {
     118           1 :         v.ref.acquire()
     119           1 : }
     120             : 
     121           1 : func (v *Value) release() {
     122           1 :         if v != nil && v.ref.release() {
     123           1 :                 v.free()
     124           1 :         }
     125             : }

Generated by: LCOV version 1.14