...

Source file src/github.com/jackc/pgx/v5/internal/stmtcache/lru_cache.go

Documentation: github.com/jackc/pgx/v5/internal/stmtcache

     1  package stmtcache
     2  
     3  import (
     4  	"container/list"
     5  
     6  	"github.com/jackc/pgx/v5/pgconn"
     7  )
     8  
     9  // LRUCache implements Cache with a Least Recently Used (LRU) cache.
    10  type LRUCache struct {
    11  	cap          int
    12  	m            map[string]*list.Element
    13  	l            *list.List
    14  	invalidStmts []*pgconn.StatementDescription
    15  }
    16  
    17  // NewLRUCache creates a new LRUCache. cap is the maximum size of the cache.
    18  func NewLRUCache(cap int) *LRUCache {
    19  	return &LRUCache{
    20  		cap: cap,
    21  		m:   make(map[string]*list.Element),
    22  		l:   list.New(),
    23  	}
    24  }
    25  
    26  // Get returns the statement description for sql. Returns nil if not found.
    27  func (c *LRUCache) Get(key string) *pgconn.StatementDescription {
    28  	if el, ok := c.m[key]; ok {
    29  		c.l.MoveToFront(el)
    30  		return el.Value.(*pgconn.StatementDescription)
    31  	}
    32  
    33  	return nil
    34  
    35  }
    36  
    37  // Put stores sd in the cache. Put panics if sd.SQL is "". Put does nothing if sd.SQL already exists in the cache or
    38  // sd.SQL has been invalidated and HandleInvalidated has not been called yet.
    39  func (c *LRUCache) Put(sd *pgconn.StatementDescription) {
    40  	if sd.SQL == "" {
    41  		panic("cannot store statement description with empty SQL")
    42  	}
    43  
    44  	if _, present := c.m[sd.SQL]; present {
    45  		return
    46  	}
    47  
    48  	// The statement may have been invalidated but not yet handled. Do not readd it to the cache.
    49  	for _, invalidSD := range c.invalidStmts {
    50  		if invalidSD.SQL == sd.SQL {
    51  			return
    52  		}
    53  	}
    54  
    55  	if c.l.Len() == c.cap {
    56  		c.invalidateOldest()
    57  	}
    58  
    59  	el := c.l.PushFront(sd)
    60  	c.m[sd.SQL] = el
    61  }
    62  
    63  // Invalidate invalidates statement description identified by sql. Does nothing if not found.
    64  func (c *LRUCache) Invalidate(sql string) {
    65  	if el, ok := c.m[sql]; ok {
    66  		delete(c.m, sql)
    67  		c.invalidStmts = append(c.invalidStmts, el.Value.(*pgconn.StatementDescription))
    68  		c.l.Remove(el)
    69  	}
    70  }
    71  
    72  // InvalidateAll invalidates all statement descriptions.
    73  func (c *LRUCache) InvalidateAll() {
    74  	el := c.l.Front()
    75  	for el != nil {
    76  		c.invalidStmts = append(c.invalidStmts, el.Value.(*pgconn.StatementDescription))
    77  		el = el.Next()
    78  	}
    79  
    80  	c.m = make(map[string]*list.Element)
    81  	c.l = list.New()
    82  }
    83  
    84  // GetInvalidated returns a slice of all statement descriptions invalidated since the last call to RemoveInvalidated.
    85  func (c *LRUCache) GetInvalidated() []*pgconn.StatementDescription {
    86  	return c.invalidStmts
    87  }
    88  
    89  // RemoveInvalidated removes all invalidated statement descriptions. No other calls to Cache must be made between a
    90  // call to GetInvalidated and RemoveInvalidated or RemoveInvalidated may remove statement descriptions that were
    91  // never seen by the call to GetInvalidated.
    92  func (c *LRUCache) RemoveInvalidated() {
    93  	c.invalidStmts = nil
    94  }
    95  
    96  // Len returns the number of cached prepared statement descriptions.
    97  func (c *LRUCache) Len() int {
    98  	return c.l.Len()
    99  }
   100  
   101  // Cap returns the maximum number of cached prepared statement descriptions.
   102  func (c *LRUCache) Cap() int {
   103  	return c.cap
   104  }
   105  
   106  func (c *LRUCache) invalidateOldest() {
   107  	oldest := c.l.Back()
   108  	sd := oldest.Value.(*pgconn.StatementDescription)
   109  	c.invalidStmts = append(c.invalidStmts, sd)
   110  	delete(c.m, sd.SQL)
   111  	c.l.Remove(oldest)
   112  }
   113  

View as plain text