class_docstr: Implements a pseudo-LRU algorithm (CLOCK) with expiration times
  
  The Clock algorithm is not kept strictly to improve performance, e.g. to
  allow get() and invalidate() to work without acquiring the lock.
class_docstr_tok: ["Implements","a","pseudo-LRU","algorithm","(","CLOCK",")","with","expiration","times","The","Clock","algorithm","is","not","kept","strictly","to","improve","performance",",","e.g",".","to","allow","get","(",")","and","invalidate","(",")","to","work","without","acquiring","the","lock","."]
docstr: Add key to the cache with value val
  
  key will expire in $timeout seconds. If key is already in cache, val
  and timeout will be updated.
docstr_tok: ["Add","key","to","the","cache","with","value","val","key","will","expire","in","$","timeout","seconds",".","If","key","is","already","in","cache",",","val","and","timeout","will","be","updated","."]
code: def put(self, key, val, timeout=None):
      """Add key to the cache with value val
  
      key will expire in $timeout seconds. If key is already in cache, val
      and timeout will be updated.
      """
      # These do not change or they are just references, no need for locking.
      maxpos = self.maxpos
      clock_refs = self.clock_refs
      clock_keys = self.clock_keys
      data = self._data
      lock = self.lock
      if timeout is None:
          timeout = self.default_timeout
  
      with self.lock:
          entry = data.get(key)
          if entry is not None:
              # We already have key. Only make sure data is up to date and
              # to remember that it was used.
              pos = entry[0]
              data[key] = (pos, val, time.time() + timeout)
              clock_refs[pos] = True
              return
          # else: key is not yet in cache. Search place to insert it.
  
          hand = self.hand
          count = 0
          max_count = 107
          while 1:
              ref = clock_refs[hand]
              if ref == True:
                  clock_refs[hand] = False
                  hand += 1
                  if hand > maxpos:
                      hand = 0
  
                  count += 1
                  if count >= max_count:
                      # We have been searching long enough. Force eviction of
                      # next entry, no matter what its status is.
                      clock_refs[hand] = False
              else:
                  oldkey = clock_keys[hand]
                  # Maybe oldkey was not in self._data to begin with. If it
                  # was, self.invalidate() in another thread might have
                  # already removed it. del() would raise KeyError, so pop().
                  oldentry = data.pop(oldkey, _MARKER)
                  if oldentry is not _MARKER:
                      self.evictions += 1
                  clock_keys[hand] = key
                  clock_refs[hand] = True
                  data[key] = (hand, val, time.time() + timeout)
                  hand += 1
                  if hand > maxpos:
                      hand = 0
                  self.hand = hand
                  break
  
imports: from abc import abstractmethod
  from abc import ABCMeta
  import threading
  import time
  import uuid
  import inspect
label_desc: Use image node_id 4 for calling the ExpiringLRUCache obj's underlying member method code with example usage: obj.put(key, val, timeout) without return types