LCOV - code coverage report
Current view: top level - pebble - read_state.go (source / functions) Coverage Total Hit
Test: 2025-02-28 08:17Z 9af14eed - meta test only.lcov Lines: 95.9 % 49 47
Test Date: 2025-02-28 08:18:29 Functions: - 0 0

            Line data    Source code
       1              : // Copyright 2019 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 pebble
       6              : 
       7              : import "sync/atomic"
       8              : 
       9              : // readState encapsulates the state needed for reading (the current version and
      10              : // list of memtables). Loading the readState is done without grabbing
      11              : // DB.mu. Instead, a separate DB.readState.RWMutex is used for
      12              : // synchronization. This mutex solely covers the current readState object which
      13              : // means it is rarely or ever contended.
      14              : //
      15              : // Note that various fancy lock-free mechanisms can be imagined for loading the
      16              : // readState, but benchmarking showed the ones considered to purely be
      17              : // pessimizations. The RWMutex version is a single atomic increment for the
      18              : // RLock and an atomic decrement for the RUnlock. It is difficult to do better
      19              : // than that without something like thread-local storage which isn't available
      20              : // in Go.
      21              : type readState struct {
      22              :         db        *DB
      23              :         refcnt    atomic.Int32
      24              :         current   *version
      25              :         memtables flushableList
      26              : }
      27              : 
      28              : // ref adds a reference to the readState.
      29            1 : func (s *readState) ref() {
      30            1 :         s.refcnt.Add(1)
      31            1 : }
      32              : 
      33              : // unref removes a reference to the readState. If this was the last reference,
      34              : // the reference the readState holds on the version is released. Requires DB.mu
      35              : // is NOT held as version.unref() will acquire it. See unrefLocked() if DB.mu
      36              : // is held by the caller.
      37            1 : func (s *readState) unref() {
      38            1 :         if s.refcnt.Add(-1) != 0 {
      39            1 :                 return
      40            1 :         }
      41            1 :         s.current.Unref()
      42            1 :         for _, mem := range s.memtables {
      43            1 :                 mem.readerUnref(true)
      44            1 :         }
      45              : 
      46              :         // The last reference to the readState was released. Check to see if there
      47              :         // are new obsolete tables to delete.
      48            1 :         s.db.maybeScheduleObsoleteTableDeletion()
      49              : }
      50              : 
      51              : // unrefLocked removes a reference to the readState. If this was the last
      52              : // reference, the reference the readState holds on the version is
      53              : // released.
      54              : //
      55              : // DB.mu must be held. See unref() if DB.mu is NOT held by the caller.
      56            1 : func (s *readState) unrefLocked() {
      57            1 :         if s.refcnt.Add(-1) != 0 {
      58            1 :                 return
      59            1 :         }
      60            1 :         s.current.UnrefLocked()
      61            1 :         for _, mem := range s.memtables {
      62            1 :                 mem.readerUnrefLocked(true)
      63            1 :         }
      64              : 
      65              :         // In this code path, the caller is responsible for scheduling obsolete table
      66              :         // deletion as necessary.
      67              : }
      68              : 
      69              : // loadReadState returns the current readState. The returned readState must be
      70              : // unreferenced when the caller is finished with it.
      71            1 : func (d *DB) loadReadState() *readState {
      72            1 :         d.readState.RLock()
      73            1 :         state := d.readState.val
      74            1 :         state.ref()
      75            1 :         d.readState.RUnlock()
      76            1 :         return state
      77            1 : }
      78              : 
      79              : // updateReadStateLocked creates a new readState from the current version and
      80              : // list of memtables. Requires DB.mu is held. If checker is not nil, it is
      81              : // called after installing the new readState.
      82            1 : func (d *DB) updateReadStateLocked(checker func(*DB) error) {
      83            1 :         s := &readState{
      84            1 :                 db:        d,
      85            1 :                 current:   d.mu.versions.currentVersion(),
      86            1 :                 memtables: d.mu.mem.queue,
      87            1 :         }
      88            1 :         s.refcnt.Store(1)
      89            1 :         s.current.Ref()
      90            1 :         for _, mem := range s.memtables {
      91            1 :                 mem.readerRef()
      92            1 :         }
      93              : 
      94            1 :         d.readState.Lock()
      95            1 :         old := d.readState.val
      96            1 :         d.readState.val = s
      97            1 :         d.readState.Unlock()
      98            1 :         if checker != nil {
      99            1 :                 if err := checker(d); err != nil {
     100            0 :                         d.opts.Logger.Fatalf("checker failed with error: %s", err)
     101            0 :                 }
     102              :         }
     103            1 :         if old != nil {
     104            1 :                 old.unrefLocked()
     105            1 :         }
     106              : }
        

Generated by: LCOV version 2.0-1