Integrate Upstream r 1862/63: purge all purgable caches from Cache Table Browser

git-svn-id: https://svn.libreccm.org/ccm/trunk@142 8810af33-2d31-482b-a856-94f89814c4df
master
pb 2009-04-19 18:40:32 +00:00
parent 1ef9fee384
commit 40428d8a99
4 changed files with 202 additions and 64 deletions

View File

@ -25,7 +25,9 @@ import com.arsdigita.bebop.util.Traversal;
import com.arsdigita.dispatcher.DispatcherHelper; import com.arsdigita.dispatcher.DispatcherHelper;
import com.arsdigita.developersupport.DeveloperSupport; import com.arsdigita.developersupport.DeveloperSupport;
import com.arsdigita.util.Assert; import com.arsdigita.util.Assert;
import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.web.ParameterMap; import com.arsdigita.web.ParameterMap;
import com.arsdigita.web.RedirectSignal;
import com.arsdigita.web.URL; import com.arsdigita.web.URL;
import com.arsdigita.web.Web; import com.arsdigita.web.Web;
import com.arsdigita.xml.Element; import com.arsdigita.xml.Element;
@ -406,16 +408,6 @@ public class PageState {
return m_response; return m_response;
} }
/**
* Return the page component with index i from the page model.
*
* @pre (i>=0) && (i < size())
* @post return != null
*/
private Component getComponent(int i) {
return m_page.getComponent(i);
}
/** /**
* The index of a component in the page model * The index of a component in the page model
* *
@ -496,7 +488,7 @@ public class PageState {
*/ */
public void setVisible(final Component c, final boolean v) { public void setVisible(final Component c, final boolean v) {
if (Assert.isEnabled()) { if (Assert.isEnabled()) {
Assert.truth(getPage().stateContains(c), Assert.isTrue(getPage().stateContains(c),
"Component" + c + " is not registered on Page " + "Component" + c + " is not registered on Page " +
getPage()); getPage());
} }
@ -703,7 +695,7 @@ public class PageState {
* @pre c == null || getPage().stateContains(c) * @pre c == null || getPage().stateContains(c)
*/ */
public void setControlEvent(Component c, String name, String value) { public void setControlEvent(Component c, String name, String value) {
Assert.assertTrue(c == null || getPage().stateContains(c), Assert.isTrue(c == null || getPage().stateContains(c),
"c == null || getPage().stateContains(c)"); "c == null || getPage().stateContains(c)");
if ( m_grabbingComponent != null && m_grabbingComponent != c ) { if ( m_grabbingComponent != null && m_grabbingComponent != c ) {
throw new IllegalStateException throw new IllegalStateException
@ -1070,4 +1062,22 @@ public class PageState {
+ "}"; + "}";
return result; return result;
} }
/**
* Clear the control event then redirect to the new page state.
*
* @param isCommitRequested indicates if a commit required before the redirect
*
* @throws RedirectSignal to the new page state
*
* @see RedirectSignal#RedirectSignal(String, boolean)
*/
public void redirectWithoutControlEvent(boolean isCommitRequested) {
clearControlEvent();
try {
throw new RedirectSignal(stateAsURL(), true);
} catch (IOException ioe) {
throw new UncheckedWrapperException(ioe);
}
}
} }

View File

@ -63,6 +63,7 @@ public class CacheServlet extends HttpServlet {
private static final String ID = "id"; private static final String ID = "id";
private static final String KEY = "key"; private static final String KEY = "key";
private static final String HASH = "hash"; private static final String HASH = "hash";
private static final String REMOVEALL = "removeAll";
// If you change this, make sure that web.xml is changed as well // If you change this, make sure that web.xml is changed as well
static final String SERVLET_URL = "/expireCache"; static final String SERVLET_URL = "/expireCache";
@ -74,15 +75,42 @@ public class CacheServlet extends HttpServlet {
protected void doGet( HttpServletRequest req, HttpServletResponse res ) { protected void doGet( HttpServletRequest req, HttpServletResponse res ) {
String id = req.getParameter( ID ); String id = req.getParameter( ID );
String key = req.getParameter( KEY ); String key = req.getParameter( KEY );
String removeAll = req.getParameter( REMOVEALL );
if (s_log.isInfoEnabled()) { if (s_log.isInfoEnabled()) {
s_log.info("Got remove request from " + req.getRemoteHost()); s_log.info("Got remove request from " + req.getRemoteHost());
} }
if (id == null || key == null) { if (id != null && key != null){
return; //normal expire cache entry request
} if (s_log.isInfoEnabled()) {
s_log.info("Got remove request from " + req.getRemoteHost());
}
String hash = req.getParameter( HASH );
expireCacheEntry(id, key, hash);
} else if (id != null && key == null && removeAll != null) {
//purge a single cache request
if (s_log.isInfoEnabled()) {
s_log.info("Got remove all entries request from " + req.getRemoteHost());
}
if(removeAll.equals("true")){
removeCacheEntries(id);
}
} else if (id == null && key == null && removeAll != null) {
//purge all caches request
if (s_log.isInfoEnabled()) {
s_log.info("Got remove all cache request from " + req.getRemoteHost());
}
if(removeAll.equals("true")){
removeAllCache();
}
} else {
s_log.error("Got an invalid cache request from " + req.getRemoteHost());
}
}
protected void expireCacheEntry(String id, String key, String hash) {
id = URLDecoder.decode(id); id = URLDecoder.decode(id);
key = URLDecoder.decode(key); key = URLDecoder.decode(key);
@ -94,7 +122,6 @@ public class CacheServlet extends HttpServlet {
s_log.debug("Removing " + key + " from cache " + id); s_log.debug("Removing " + key + " from cache " + id);
final String hash = req.getParameter( HASH );
final Integer hashCode = getHashCode(hash); final Integer hashCode = getHashCode(hash);
if (hashCode == null) { if (hashCode == null) {
// unconditionally remove // unconditionally remove
@ -104,6 +131,25 @@ public class CacheServlet extends HttpServlet {
} }
} }
protected void removeCacheEntries(String id) {
id = URLDecoder.decode(id);
final CacheTable cache = CacheTable.getCache( id );
if (cache == null) {
s_log.debug("No cache with id " + id);
return;
}
s_log.debug("Removing all entries from cache " + id);
// unconditionally remove
cache.removeAllEntriesLocally();
}
protected void removeAllCache() {
s_log.debug("Removing all Cache tables");
// unconditionally remove all
CacheTable.removeAllCacheTablesLocally();
}
private Integer getHashCode(final String hash) { private Integer getHashCode(final String hash) {
if (hash == null) { if (hash == null) {
return null; return null;
@ -135,6 +181,32 @@ public class CacheServlet extends HttpServlet {
} }
/**
* remote all entries from all purge-able tables in the peer's.
*
* The fact that there is no ID parameter tells the
* peers to purge all cache tables.
*/
static void removeAllFromPeers() {
final ParameterMap params = new ParameterMap();
params.setParameter(REMOVEALL, "true");
notifyPeers(params);
}
/**
* remote all entries from the peer's cache table with an id of cacheID.
*
* @param cacheID id of the cache table to purge
*/
static void removeAllEntriesFromPeersTable(String cacheID) {
final ParameterMap params = new ParameterMap();
params.setParameter(ID, cacheID);
params.setParameter(REMOVEALL, "true");
notifyPeers(params);
}
/** /**
* Sometimes we need to remove entries only from peer webservers. * Sometimes we need to remove entries only from peer webservers.
*/ */
@ -159,6 +231,10 @@ public class CacheServlet extends HttpServlet {
private static void notifyPeers(final String id, private static void notifyPeers(final String id,
final String key, final String key,
final String hash) { final String hash) {
notifyPeers(makeParameterMap(id, key, hash));
}
private static void notifyPeers(ParameterMap params) {
if (!Web.getConfig().getDeactivateCacheHostNotifications()) { if (!Web.getConfig().getDeactivateCacheHostNotifications()) {
s_log.debug("about to notify peers"); s_log.debug("about to notify peers");
final Session session = SessionManager.getSession(); final Session session = SessionManager.getSession();
@ -174,7 +250,7 @@ public class CacheServlet extends HttpServlet {
f.set("currPort", new Integer(current.getPort())); f.set("currPort", new Integer(current.getPort()));
while (hosts.next()) { while (hosts.next()) {
final Host host = (Host) hosts.getDomainObject(); final Host host = (Host) hosts.getDomainObject();
notifyPeer(host, makeParameterMap(id, key, hash)); notifyPeer(host, params);
} }
} }
} }

View File

@ -27,6 +27,7 @@ import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -229,19 +230,14 @@ public class CacheTable {
} }
public void setPurgeAllowed(boolean purgeAllowed) { public void setPurgeAllowed(boolean purgeAllowed) {
this.purgeAllowed = purgeAllowed; this.purgeAllowed = purgeAllowed;
} }
public boolean isPurgeAllowed() { public boolean isPurgeAllowed() {
return purgeAllowed; return purgeAllowed;
} }
private void removeLRUEntry() {
m_list.removeLRUEntry();
}
/** /**
* A convenience wrapper around {@link #put(String, Object)}. * A convenience wrapper around {@link #put(String, Object)}.
* *
@ -425,6 +421,39 @@ public class CacheTable {
} }
public synchronized void removeAllEntriesLocally() {
m_list.clear();
if (s_log.isDebugEnabled()) {
s_log.debug("removed all entries from cache table " + m_cacheID);
}
}
public static void removeAllCacheTables() {
if (s_log.isDebugEnabled()) {
s_log.debug("remove all entries from all purge-able cache tables");
}
removeAllCacheTablesLocally();
CacheServlet.removeAllFromPeers();
}
/**
* Iterator over all CacheTables in the cache
* and clear all purge-able ones
*/
public static synchronized void removeAllCacheTablesLocally() {
for(Iterator it = s_caches.values().iterator(); it.hasNext(); ) {
CacheTable ct = (CacheTable)it.next();
if (ct.isPurgeAllowed()) {
ct.removeAll();
if (s_log.isDebugEnabled()) {
s_log.debug("removed all entries from cache table " + ct.m_cacheID);
}
}
}
}
/** /**
* <p> Retrieves the object stored in cache. If no object by the * <p> Retrieves the object stored in cache. If no object by the
* passed key can be found in cache (maybe because it's expired or * passed key can be found in cache (maybe because it's expired or
@ -468,6 +497,7 @@ public class CacheTable {
String isShared(String tableID); String isShared(String tableID);
boolean isPurgeAllowed(String tableID); boolean isPurgeAllowed(String tableID);
void purge(String tableID); void purge(String tableID);
void purgeAll();
} }
private static class BrowserImpl implements Browser { private static class BrowserImpl implements Browser {
@ -499,15 +529,19 @@ public class CacheTable {
} }
public boolean isPurgeAllowed(String tableID) { public boolean isPurgeAllowed(String tableID) {
return getCacheTable(tableID).isPurgeAllowed(); return getCacheTable(tableID).isPurgeAllowed();
} }
public void purge(String tableID) { public void purge(String tableID) {
CacheTable table = getCacheTable(tableID); CacheTable table = getCacheTable(tableID);
if (!table.isPurgeAllowed()) { if (!table.isPurgeAllowed()) {
throw new RuntimeException("Table "+tableID+" can't be purged."); throw new RuntimeException("Table "+tableID+" can't be purged.");
} }
table.removeAll(); table.removeAll();
}
public void purgeAll() {
CacheTable.removeAllCacheTables();
} }
private static CacheTable getCacheTable(String tableID) { private static CacheTable getCacheTable(String tableID) {

View File

@ -18,19 +18,6 @@
*/ */
package com.arsdigita.webdevsupport; package com.arsdigita.webdevsupport;
import com.arsdigita.bebop.ControlLink;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.bebop.table.TableModelBuilder;
import com.arsdigita.caching.CacheTable;
import com.arsdigita.caching.CacheTable.TimestampedEntry;
import com.arsdigita.util.LockableImpl;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
@ -40,6 +27,23 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import com.arsdigita.bebop.ActionLink;
import com.arsdigita.bebop.ControlLink;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.ListPanel;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.bebop.table.TableModelBuilder;
import com.arsdigita.caching.CacheTable;
import com.arsdigita.caching.CacheTable.TimestampedEntry;
import com.arsdigita.util.LockableImpl;
/** /**
* @author Vadim Nasardinov (vadimn@redhat.com) * @author Vadim Nasardinov (vadimn@redhat.com)
@ -56,22 +60,34 @@ final class CacheTableBrowser extends SimpleContainer {
m_tableContents = new CacheTableContents(); m_tableContents = new CacheTableContents();
m_listOfTables.addTableActionListener(new TableActionListener() { m_listOfTables.addTableActionListener(new TableActionListener() {
public void cellSelected(TableActionEvent ev) { public void cellSelected(TableActionEvent ev) {
int column = ev.getColumn().intValue(); int column = ev.getColumn().intValue();
switch (column) { switch (column) {
case 0: case 0:
PageState state = ev.getPageState(); PageState state = ev.getPageState();
m_tableContents.setTableID(state,(String) ev.getRowKey()); m_tableContents.setTableID(state, (String) ev.getRowKey());
break; break;
case 5: case 5:
CacheTable.BROWSER.purge((String) ev.getRowKey()); CacheTable.BROWSER.purge((String) ev.getRowKey());
break; ev.getPageState().redirectWithoutControlEvent(false);
default: default:
break; break;
}
} }
}
public void headSelected(TableActionEvent e) { } public void headSelected(TableActionEvent e) {
}); }
});
ActionLink purgeAllLink = new ActionLink("Purge all caches");
purgeAllLink.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
CacheTable.BROWSER.purgeAll();
e.getPageState().redirectWithoutControlEvent(false);
}
});
ListPanel container = new ListPanel(false);
container.add(purgeAllLink);
add(container);
add(m_listOfTables); add(m_listOfTables);
add(m_tableContents); add(m_tableContents);
@ -137,7 +153,11 @@ final class CacheTableBrowser extends SimpleContainer {
return String.valueOf(CacheTable.BROWSER.isShared(m_key)); return String.valueOf(CacheTable.BROWSER.isShared(m_key));
case 5: case 5:
if (CacheTable.BROWSER.isPurgeAllowed(m_key)) { if (CacheTable.BROWSER.isPurgeAllowed(m_key)) {
return new ControlLink(new Label("purge")); if (CacheTable.BROWSER.getCurrentSize(m_key) > 0) {
return new ControlLink(new Label("purge"));
} else {
return new Label("(empty)");
}
} else { } else {
return new Label("can't be purged"); return new Label("can't be purged");
} }
@ -161,8 +181,6 @@ final class CacheTableBrowser extends SimpleContainer {
private final static String TABLE_ID_ATTR = private final static String TABLE_ID_ATTR =
CacheTableContents.class.getName(); CacheTableContents.class.getName();
private String m_tableID;
public CacheTableContents() { public CacheTableContents() {
super(new ModelBuilder(), super(new ModelBuilder(),
new String[] { "Key", "Class", "Value", "Hits", "Hash code", "Timestamp" }); new String[] { "Key", "Class", "Value", "Hits", "Hash code", "Timestamp" });