Beispiel #1
0
 def tell(self, key, value, time, ttl, from_client):
     if value is None:
         # deletes cannot have a TTL
         ttl = None
     send_update = True
     always_send_update = False
     # remove no-store flag
     if key.endswith(FLAG_NO_STORE):
         key = key[:-len(FLAG_NO_STORE)]
         always_send_update = True
     try:
         category, subkey = key.rsplit('/', 1)
     except ValueError:
         category = 'nocat'
         subkey = key
     newcats = [category]
     if category in self._rewrites:
         newcats.extend(self._rewrites[category])
     for newcat in newcats:
         key = newcat + '/' + subkey
         with self._db_lock:
             queue = deque([CacheEntry(None, None, None)], self.maxentries)
             entries = self._db.setdefault(key, queue)
             lastent = entries[-1]
             if lastent.value == value and not lastent.ttl:
                 # not a real update
                 send_update = False
             entries.append(CacheEntry(time, ttl, value))
         if send_update or always_send_update:
             for client in self._server._connected.values():
                 if client is not from_client and client.is_active():
                     client.update(key, OP_TELL, value or '', time, ttl)
Beispiel #2
0
    def decode(self, buf):
        try:
            ns_entry = deserialise_ns10(buf)
            key = ns_entry.key if ns_entry.key else None
            ttl = ns_entry.ttl if ns_entry.ttl != 0 else None
            value = ns_entry.value if ns_entry.value else None

            entry = CacheEntry(ns_entry.time_stamp, ttl, value)
            entry.expired = ns_entry.expired
            return key, entry
        except Exception as error:
            self.log.error('Could not decode ns10 cache entry: %s', error)
            return None, None
Beispiel #3
0
 def lock(self, key, value, time, ttl):
     """Lock handling code, common to both subclasses."""
     with self._lock_lock:
         entry = self._locks.get(key)
         # want to lock?
         req, client_id = value[0], value[1:]
         if req == OP_LOCK_LOCK:
             if entry and entry.value != client_id and \
                (not entry.ttl or entry.time + entry.ttl >= currenttime()):
                 # still locked by different client, deny (tell the client
                 # the current client_id though)
                 self.log.debug(
                     'lock request %s=%s, but still locked by %s',
                     key, client_id, entry.value)
                 return [key + OP_LOCK + entry.value + '\n']
             else:
                 # not locked, expired or locked by same client, overwrite
                 ttl = ttl or 600  # set a maximum time to live
                 self.log.debug('lock request %s=%s ttl %s, accepted',
                                key, client_id, ttl)
                 self._locks[key] = CacheEntry(time, ttl, client_id)
                 return [key + OP_LOCK + '\n']
         # want to unlock?
         elif req == OP_LOCK_UNLOCK:
             if entry and entry.value != client_id:
                 # locked by different client, deny
                 self.log.debug('unlock request %s=%s, but locked by %s',
                                key, client_id, entry.value)
                 return [key + OP_LOCK + entry.value + '\n']
             else:
                 # unlocked or locked by same client, allow
                 self.log.debug('unlock request %s=%s, accepted',
                                key, client_id)
                 self._locks.pop(key, None)
                 return [key + OP_LOCK + '\n']
Beispiel #4
0
 def tell(self, key, value, time, ttl, from_client):
     # self.log.debug('updating %s %s', key, value)
     if value is None:
         # deletes cannot have a TTL
         ttl = None
     now = currenttime()
     if time is None:
         time = now
     store_on_disk = True
     if key.endswith(FLAG_NO_STORE):
         key = key[:-len(FLAG_NO_STORE)]
         store_on_disk = False
     with self._cat_lock:
         if now > self._nextmidnight:
             self._rollover()
     try:
         category, subkey = key.rsplit('/', 1)
     except ValueError:
         category = 'nocat'
         subkey = key
     newcats = [category]
     if category in self._rewrites:
         newcats.extend(self._rewrites[category])
     for newcat in newcats:
         with self._cat_lock:
             if newcat not in self._cat:
                 # the first item, fd, is created on demand below
                 self._cat[newcat] = [None, threading.Lock(), {}]
             fd, lock, db = self._cat[newcat]
         update = True
         with lock:
             if subkey in db:
                 entry = db[subkey]
                 if entry.value == value and not entry.expired:
                     # existing entry with the same value: update the TTL
                     # but don't write an update to the history file
                     entry.time = time
                     entry.ttl = ttl
                     update = not store_on_disk
                 elif value is None and entry.expired:
                     # do not delete old value, it is already expired
                     update = not store_on_disk
             if update:
                 db[subkey] = CacheEntry(time, ttl, value)
                 if store_on_disk:
                     if fd is None:
                         fd = self._create_fd(newcat)
                         self._cat[newcat][0] = fd
                     fd.write('%s\t%s\t%s\t%s\n' %
                              (subkey, time, ttl and '-' or
                               (value and '+' or '-'), value or '-'))
                     fd.flush()
         if update and (not ttl or time + ttl > now):
             key = newcat + '/' + subkey
             for client in self._server._connected.values():
                 if client is not from_client:
                     client.update(key, OP_TELL, value or '', time, ttl)
Beispiel #5
0
 def _read_one_storefile_v2(self, filename, fd):
     db = {}
     for line in fd:
         if '\x00' in line:
             self.log.warning('found nullbyte in store file %s', filename)
             continue
         try:
             subkey, time, hasttl, value = line.rstrip().split(None, 3)
             if hasttl == '+':
                 # the value is valid indefinitely, so we can use it
                 db[subkey] = CacheEntry(float(time), None, value)
             elif value != '-':
                 # the value is not valid indefinitely, add it but mark as expired
                 db[subkey] = CacheEntry(float(time), None, value)
                 db[subkey].expired = True
             elif subkey in db:  # implied: value == '-'
                 # the value is already present, but now explicitly invalidated
                 # => mark it as expired
                 db[subkey].expired = True
         except Exception:
             self.log.warning(
                 'could not interpret line from '
                 'cache file %s: %r',
                 filename,
                 line,
                 exc=1)
     return db
Beispiel #6
0
def decode(buf):
    # Check for the correct file identifier
    identifier = buf[4:8].decode('utf-8')
    if identifier != file_identifier:
        session.log.error('Incorrect file identifier found: %s', identifier)
        return None, None

    # Convert the buffer to FB class
    fb_entry = CacheEntryFB.CacheEntry.GetRootAsCacheEntry(buf, 0)

    # Capture the default values of key, ttl and set them to None
    key = fb_entry.Key() if fb_entry.Key() else None
    ttl = fb_entry.Ttl() if fb_entry.Ttl() != 0 else None

    # Try to get the value if it was written
    try:
        value = fb_entry.Value()
    except Exception:
        value = None

    entry = NicosCacheEntry(fb_entry.Time(), ttl, value)
    entry.expired = bool(fb_entry.Expired())
    return key, entry
Beispiel #7
0
 def decode(self, coded):
     edict = self._decoder.decode(coded)
     entry = CacheEntry(edict['time'], edict['ttl'], edict['value'])
     entry.expired = edict['expired']
     key = edict['key']
     return key, entry