Example #1
0
  /**
   * Put an object into the cache specifying both the key to use and the cache groups the object
   * belongs to.
   *
   * @param key Key of the object in the cache
   * @param groups The cache groups to add the object to
   * @param content The object to cache
   * @param policy Object that implements the refresh policy logic
   */
  public void putInCache(
      String key, Object content, String[] groups, EntryRefreshPolicy policy, String origin) {
    CacheEntry cacheEntry = this.getCacheEntry(key, policy, origin);
    boolean isNewEntry = cacheEntry.isNew();

    // [CACHE-118] If we have an existing entry, create a new CacheEntry so we can still access the
    // old one later
    if (!isNewEntry) {
      cacheEntry = new CacheEntry(key, policy);
    }

    cacheEntry.setContent(content);
    cacheEntry.setGroups(groups);
    cacheMap.put(key, cacheEntry);

    // Signal to any threads waiting on this update that it's now ready for them
    // in the cache!
    completeUpdate(key);

    if (listenerList.getListenerCount() > 0) {
      CacheEntryEvent event = new CacheEntryEvent(this, cacheEntry, origin);

      if (isNewEntry) {
        dispatchCacheEntryEvent(CacheEntryEventType.ENTRY_ADDED, event);
      } else {
        dispatchCacheEntryEvent(CacheEntryEventType.ENTRY_UPDATED, event);
      }
    }
  }
Example #2
0
  /**
   * Flush a cache entry. On completion of the flush, a <tt>CacheEntryEventType.ENTRY_FLUSHED</tt>
   * event is fired.
   *
   * @param entry The entry to flush
   * @param origin The origin of this flush event (optional)
   */
  private void flushEntry(CacheEntry entry, String origin) {
    String key = entry.getKey();

    // Flush the object itself
    entry.flush();

    if (!entry.isNew()) {
      // Update the entry's state in the map
      cacheMap.put(key, entry);
    }

    // Trigger an ENTRY_FLUSHED event. [CACHE-107] Do this for all flushes.
    if (listenerList.getListenerCount() > 0) {
      CacheEntryEvent event = new CacheEntryEvent(this, entry, origin);
      dispatchCacheEntryEvent(CacheEntryEventType.ENTRY_FLUSHED, event);
    }
  }
Example #3
0
  /**
   * Retrieve an object from the cache specifying its key.
   *
   * @param key Key of the object in the cache.
   * @param refreshPeriod How long before the object needs refresh. To allow the object to stay in
   *     the cache indefinitely, supply a value of {@link CacheEntry#INDEFINITE_EXPIRY}.
   * @param cronExpiry A cron expression that specifies fixed date(s) and/or time(s) that this cache
   *     entry should expire on.
   * @return The object from cache
   * @throws NeedsRefreshException Thrown when the object either doesn't exist, or exists but is
   *     stale. When this exception occurs, the CacheEntry corresponding to the supplied key will be
   *     locked and other threads requesting this entry will potentially be blocked until the caller
   *     repopulates the cache. If the caller choses not to repopulate the cache, they <em>must</em>
   *     instead call {@link #cancelUpdate(String)}.
   */
  public Object getFromCache(String key, int refreshPeriod, String cronExpiry)
      throws NeedsRefreshException {
    CacheEntry cacheEntry = this.getCacheEntry(key, null, null);

    Object content = cacheEntry.getContent();
    CacheMapAccessEventType accessEventType = CacheMapAccessEventType.HIT;

    boolean reload = false;

    // Check if this entry has expired or has not yet been added to the cache. If
    // so, we need to decide whether to block, serve stale content or throw a
    // NeedsRefreshException
    if (this.isStale(cacheEntry, refreshPeriod, cronExpiry)) {

      // Get access to the EntryUpdateState instance and increment the usage count during the
      // potential sleep
      EntryUpdateState updateState = getUpdateState(key);
      // System.out.println("Stale:" + updateState.state + EntryUpdateState.NOT_YET_UPDATING);
      try {
        synchronized (updateState) {
          if (updateState.isAwaitingUpdate() || updateState.isCancelled()) {
            // No one else is currently updating this entry - grab ownership
            updateState.startUpdate();

            if (cacheEntry.isNew()) {
              accessEventType = CacheMapAccessEventType.MISS;
            } else {
              accessEventType = CacheMapAccessEventType.STALE_HIT;
            }
          } else if (updateState.isUpdating()) {
            // Another thread is already updating the cache. We block if this
            // is a new entry, or blocking mode is enabled. Either putInCache()
            // or cancelUpdate() can cause this thread to resume.
            System.out.println("Yes - it's updating...");
            if (cacheEntry.isNew() || blocking) {
              do {
                try {
                  System.out.println("updateState was in:" + cacheEntry.isNew() + ":" + blocking);
                  updateState.wait();
                } catch (InterruptedException e) {
                }
              } while (updateState.isUpdating());

              if (updateState.isCancelled()) {
                // The updating thread cancelled the update, let this one have a go.
                // This increments the usage count for this EntryUpdateState instance
                updateState.startUpdate();

                if (cacheEntry.isNew()) {
                  accessEventType = CacheMapAccessEventType.MISS;
                } else {
                  accessEventType = CacheMapAccessEventType.STALE_HIT;
                }
              } else if (updateState.isComplete()) {
                reload = true;
              } else {
                log.error("Invalid update state for cache entry " + key);
              }
            }
          } else {
            reload = true;
          }
        }
      } finally {
        // Make sure we release the usage count for this EntryUpdateState since we don't use it
        // anymore. If the current thread started the update, then the counter was
        // increased by one in startUpdate()
        releaseUpdateState(updateState, key);
      }
    }

    // If reload is true then another thread must have successfully rebuilt the cache entry
    if (reload) {
      cacheEntry = (CacheEntry) cacheMap.get(key);

      if (cacheEntry != null) {
        content = cacheEntry.getContent();
      } else {
        log.error("Could not reload cache entry after waiting for it to be rebuilt");
      }
    }

    dispatchCacheMapAccessEvent(accessEventType, cacheEntry, null);

    // If we didn't end up getting a hit then we need to throw a NRE
    if (accessEventType != CacheMapAccessEventType.HIT) {
      throw new NeedsRefreshException(content);
    }

    return content;
  }