...

Source file src/golang.org/x/mod/sumdb/storage/mem.go

Documentation: golang.org/x/mod/sumdb/storage

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package storage
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"math/rand"
    11  	"sync"
    12  )
    13  
    14  // Mem is an in-memory implementation of Storage.
    15  // It is meant for tests and does not store any data to persistent storage.
    16  //
    17  // The zero value is an empty Mem ready for use.
    18  type Mem struct {
    19  	mu    sync.RWMutex
    20  	table map[string]string
    21  }
    22  
    23  // A memTx is a transaction in a Mem.
    24  type memTx struct {
    25  	m      *Mem
    26  	writes []Write
    27  }
    28  
    29  // errRetry is an internal sentinel indicating that the transaction should be retried.
    30  // It is never returned to the caller.
    31  var errRetry = errors.New("retry")
    32  
    33  // ReadOnly runs f in a read-only transaction.
    34  func (m *Mem) ReadOnly(ctx context.Context, f func(context.Context, Transaction) error) error {
    35  	tx := &memTx{m: m}
    36  	for {
    37  		err := func() error {
    38  			m.mu.Lock()
    39  			defer m.mu.Unlock()
    40  
    41  			if err := f(ctx, tx); err != nil {
    42  				return err
    43  			}
    44  			// Spurious retry with 10% probability.
    45  			if rand.Intn(10) == 0 {
    46  				return errRetry
    47  			}
    48  			return nil
    49  		}()
    50  		if err != errRetry {
    51  			return err
    52  		}
    53  	}
    54  }
    55  
    56  // ReadWrite runs f in a read-write transaction.
    57  func (m *Mem) ReadWrite(ctx context.Context, f func(context.Context, Transaction) error) error {
    58  	tx := &memTx{m: m}
    59  	for {
    60  		err := func() error {
    61  			m.mu.Lock()
    62  			defer m.mu.Unlock()
    63  
    64  			tx.writes = []Write{}
    65  			if err := f(ctx, tx); err != nil {
    66  				return err
    67  			}
    68  			// Spurious retry with 10% probability.
    69  			if rand.Intn(10) == 0 {
    70  				return errRetry
    71  			}
    72  			if m.table == nil {
    73  				m.table = make(map[string]string)
    74  			}
    75  			for _, w := range tx.writes {
    76  				if w.Value == "" {
    77  					delete(m.table, w.Key)
    78  				} else {
    79  					m.table[w.Key] = w.Value
    80  				}
    81  			}
    82  			return nil
    83  		}()
    84  		if err != errRetry {
    85  			return err
    86  		}
    87  	}
    88  }
    89  
    90  // ReadValues returns the values associated with the given keys.
    91  func (tx *memTx) ReadValues(ctx context.Context, keys []string) ([]string, error) {
    92  	vals := make([]string, len(keys))
    93  	for i, key := range keys {
    94  		vals[i] = tx.m.table[key]
    95  	}
    96  	return vals, nil
    97  }
    98  
    99  // ReadValue returns the value associated with the single key.
   100  func (tx *memTx) ReadValue(ctx context.Context, key string) (string, error) {
   101  	return tx.m.table[key], nil
   102  }
   103  
   104  // BufferWrites buffers a list of writes to be applied
   105  // to the table when the transaction commits.
   106  // The changes are not visible to reads within the transaction.
   107  // The map argument is not used after the call returns.
   108  func (tx *memTx) BufferWrites(list []Write) error {
   109  	if tx.writes == nil {
   110  		panic("BufferWrite on read-only transaction")
   111  	}
   112  	tx.writes = append(tx.writes, list...)
   113  	return nil
   114  }
   115  

View as plain text