LCOV - code coverage report
Current view: top level - pebble - read_state.go (source / functions) Hit Total Coverage
Test: 2024-03-03 08:16Z dd51d85c - tests + meta.lcov Lines: 47 49 95.9 %
Date: 2024-03-03 08:17:33 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           2 : func (s *readState) ref() {
      30           2 :         s.refcnt.Add(1)
      31           2 : }
      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           2 : func (s *readState) unref() {
      38           2 :         if s.refcnt.Add(-1) != 0 {
      39           2 :                 return
      40           2 :         }
      41           2 :         s.current.Unref()
      42           2 :         for _, mem := range s.memtables {
      43           2 :                 mem.readerUnref(true)
      44           2 :         }
      45             : 
      46             :         // The last reference to the readState was released. Check to see if there
      47             :         // are new obsolete tables to delete.
      48           2 :         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           2 : func (s *readState) unrefLocked() {
      57           2 :         if s.refcnt.Add(-1) != 0 {
      58           2 :                 return
      59           2 :         }
      60           2 :         s.current.UnrefLocked()
      61           2 :         for _, mem := range s.memtables {
      62           2 :                 mem.readerUnrefLocked(true)
      63           2 :         }
      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           2 : func (d *DB) loadReadState() *readState {
      72           2 :         d.readState.RLock()
      73           2 :         state := d.readState.val
      74           2 :         state.ref()
      75           2 :         d.readState.RUnlock()
      76           2 :         return state
      77           2 : }
      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           2 : func (d *DB) updateReadStateLocked(checker func(*DB) error) {
      83           2 :         s := &readState{
      84           2 :                 db:        d,
      85           2 :                 current:   d.mu.versions.currentVersion(),
      86           2 :                 memtables: d.mu.mem.queue,
      87           2 :         }
      88           2 :         s.refcnt.Store(1)
      89           2 :         s.current.Ref()
      90           2 :         for _, mem := range s.memtables {
      91           2 :                 mem.readerRef()
      92           2 :         }
      93             : 
      94           2 :         d.readState.Lock()
      95           2 :         old := d.readState.val
      96           2 :         d.readState.val = s
      97           2 :         d.readState.Unlock()
      98           2 :         if checker != nil {
      99           2 :                 if err := checker(d); err != nil {
     100           0 :                         d.opts.Logger.Fatalf("checker failed with error: %s", err)
     101           0 :                 }
     102             :         }
     103           2 :         if old != nil {
     104           2 :                 old.unrefLocked()
     105           2 :         }
     106             : }

Generated by: LCOV version 1.14