RE: Publication date
"ghislain\.cussonneau" <[email protected]>
| Newsgroups | gmane.comp.cms.jahia.template |
|---|---|
| Message-ID | <[email protected]> |
Ok,
I've test with JMeter my server (100 concurents users load in 10 seconds and read 10 times a list of pages on the site) with and without this personal OperationManager and after charging both Jahia and Apache cache (1 user load 2 times all the list of pages). The results are the following :
With Personal OperationManager : Average=500ms, Median=125ms, 90%=1400, Min=0, Max=20000, Errors=0, Flow=6.0/sec, KB/sec=350
Without Personal OperationManager : Average=600ms, Median=150ms, 90%=1700, Min=0, Max=15000, Errors=0, Flow=5.7/sec, KB/sec=300
So I would use your adding code : Thanks ! I think so about that : I would try to add my JSP/Template Header send code in the OperationManager's one. In this way, all my sites would have the "send cache header" support ! It would very better...
Just a correction on your code : the correct one for integration with my HtmlCacheEntry class is :
//--------------------- BEGIN: NEW CODE ---------------------------
//return an HTTP 304 Not modified if cache entry hasn't been changed since last request
HttpServletRequest realReq = jParams.getRealRequest();
long modSinceHeader = realReq.getDateHeader("If-Modified-Since");
if (modSinceHeader !=-1) {
Date modSinceHeaderDate = new Date(modSinceHeader);
Date cacheLastMod = new Date();
cacheLastMod.setTime(htmlEntry.getContentTimestamp());
if ( cacheLastMod.before(modSinceHeaderDate)) {
realResp.setStatus(304);
return;
}
}
//--------------------- END: NEW CODE ---------------------------
REGARDSGhislain
Ghislain,
In order to apply my aforementioned modifications to the Jahia 5.0s org.jahia.operations.valves.CacheReadValve class to Jahia versions 4.0 or 4.1, you need to modify the org.jahia.operations.OperationManager.handleOperations() method (which functionally overlaps):
if (jParams.settings().lookupBoolean(SettingsBean.OUTPUT_CACHE_ACTIVATED)) {
/** we only do HTML content caching if it is a core engine call
* and if the HTTP method is GET. We might extend on this later
* on but for the sake of simplicity of implementation we
* restrict it for now. We might be interested in doing more
* work here in order to cache more often.
*/
if ( ("core".equals(jParams.getEngine())) &&
(jParams.getHttpMethod() == ParamBean.GET_METHOD) &&
(ParamBean.CACHE_ON.equals(jParams.getCacheStatus()))
)
{
// logger.debug("Requested page is : " + jParams.getPageID() );
String entryKey = htmlCache.computeEntryKey(
Integer.toString (jParams.getPageID ()),
jParams.getUser().getUsername(),
curLanguageCode,
workflowState,
jParams.getUserAgent ());
CacheEntry cacheEntry = htmlCache.getCacheEntry(entryKey);
if (cacheEntry != null) {
// logger.debug ("Found HTML page in cache!!!!!!!!!!!!!!!!!!");
HtmlCacheEntry htmlEntry = (HtmlCacheEntry)cacheEntry.getObject();
String htmlContent = htmlEntry.getContentBody();
if (!cacheEntry.getOperationMode().equals(jParams.getOperationMode())) {
logger.debug("Cache entry mode is NOT equal to current mode, flushing page entry and generating page...");
htmlCache.remove (entryKey);
} else {
if (htmlContent != null) {
logger.debug("Found content in cache, writing directly bypassing processing...");
HttpServletResponse realResp = jParams.getRealResponse();
//--------------------- BEGIN: NEW CODE ---------------------------
//return an HTTP 304 Not modified if cache entry hasn't been changed since last request
HttpServletRequest realReq = jParams.getRealRequest();
long modSinceHeader = realReq.getDateHeader("If-Modified-Since");
if (modSinceHeader !=-1) {
Date modSinceHeaderDate = new Date(modSinceHeader);
Date cacheLastMod = htmlEntry.getContentTimestamp();
if ( cacheLastMod.before(modSinceHeaderDate)) {
realResp.setStatus(304);
return;
}
}
//--------------------- END: NEW CODE ---------------------------
String contentType = htmlEntry.getContentType();
if (contentType != null) {
realResp.setContentType(contentType);
logger.debug("Sending content type : [" + contentType + "]");
}
try {
ServletOutputStream outputStream = realResp.getOutputStream();
OutputStreamWriter streamWriter = new
OutputStreamWriter(outputStream);
if (contentType != null) {
int charsetPos = contentType.toLowerCase().indexOf("charset=");
if (charsetPos != -1) {
String encoding = contentType.substring(charsetPos + "charset=".length()).toUpperCase();
logger.debug("Using streamWriter with encoding : " + encoding);
streamWriter = new
OutputStreamWriter (outputStream, encoding);
}
}
Regards
Marc
>
From: Marc Cardle [mailto:[email protected]]
Sent: 13 December 2005 11:28
To: [email protected]
Subject: RE: Publication date
Ghislain,
Thanks for your contribution! This code will be particularly useful for people running Jahia 4.0 and 4.1 (with or without a front-end Apache server). In Jahia 5.0, we are developing an ESI-enabled webcache server which supports more advanced caching features. It will replace, and be more efficient, than a front-end Apache server.
In the meantime, why not go even further with your code and use the If-Not-Modified HTTP header? If Jahia detects such a header in the request and the cache entry is old enough, it will quit processing the page and return an HTTP 304 Not-Modified header ( http://www.checkupdown.com/status/E304.html ).
The best place to add this functionality would be in the org.jahia.operations.valves.CacheReadValve class. I have written a (untested) mockup of the necessary changes below which you are welcome to try. Check for the BEGIN: NEW CODE tagged section. Again, youd need to recompile the CacheReadValve class and place it in the appropriate package directory in your webapps/jahia/WEB-INF/classes directory.
public void invoke (Object context, ValveContext valveContext)
throws PipelineException {
ProcessingContext processingContext = (ProcessingContext) context;
// first order of business is to do all cache processing, in order to
// minimize what we have to do.
if (processingContext.settings().lookupBoolean(SettingsBean.
OUTPUT_CACHE_ACTIVATED)) {
/** we only do HTML content caching if it is a core engine call
* and if the HTTP method is GET. We might extend on this later
* on but for the sake of simplicity of implementation we
* restrict it for now. We might be interested in doing more
* work here in order to cache more often.
*/
HtmlCache htmlCache = null;
try {
// Get the HTML cache instance
htmlCache = ServicesRegistry.getInstance().getCacheService().getHtmlCacheInstance();
} catch (JahiaInitializationException ex) {
throw new PipelineException(ex);
}
// extract the workflow state out of the parameters bean
int workflowState = processingContext.getEntryLoadRequest().
getWorkflowState();
// Get the language code
String curLanguageCode = LanguageCodeConverters.localeToLanguageTag(
processingContext.getLocale());
if ( ("core".equals(processingContext.getEngine())) &&
(processingContext.getHttpMethod() == ProcessingContext.GET_METHOD) &&
(ProcessingContext.CACHE_ON.equals(processingContext.getCacheStatus()))
) {
// logger.debug("Requested page is : " + jParams.getObjectKey() );
GroupCacheKey entryKey = htmlCache.computeEntryKey(
Integer.toString(processingContext.getPageID()),
processingContext.getUser().getUsername(),
curLanguageCode,
workflowState,
processingContext.getUserAgent());
CacheEntry cacheEntry = htmlCache.getCacheEntry(entryKey);
if (cacheEntry != null) {
// logger.debug ("Found HTML page in cache!!!!!!!!!!!!!!!!!!");
HtmlCacheEntry htmlEntry = (HtmlCacheEntry) cacheEntry.
getObject();
String htmlContent = htmlEntry.getContentBody();
if (!cacheEntry.getOperationMode().equals(
processingContext.getOperationMode())) {
logger.debug("Cache entry mode is NOT equal to current mode, flushing page entry and generating page...");
htmlCache.remove(entryKey);
} else {
if (htmlContent != null) {
logger.debug(
"Found content in cache, writing directly bypassing processing...");
HttpServletResponse realResp = ((ParamBean)processingContext).
getRealResponse();
String contentType = htmlEntry.getContentType();
//--------------------- BEGIN: NEW CODE ---------------------------
//return an HTTP 304 Not modified if cache entry hasn't been changed since last request
HttpServletRequest realReq = ((ParamBean)processingContext).
getRealRequest();
long modSinceHeader = realReq.getDateHeader("If-Modified-Since");
if (modSinceHeader !=-1) {
Date modSinceHeaderDate = new Date(modSinceHeader);
Date cacheLastMod = htmlEntry.getContentTimestamp();
if ( cacheLastMod.before(modSinceHeaderDate)) {
realResp.setStatus(304);
return;
}
}
//--------------------- END: NEW CODE ---------------------------
if (contentType != null) {
realResp.setContentType(contentType);
logger.debug("Sending content type : [" +
contentType + "]");
}
try {
ServletOutputStream outputStream = realResp.
getOutputStream();
OutputStreamWriter streamWriter = new
OutputStreamWriter(outputStream);
if (contentType != null) {
int charsetPos = contentType.toLowerCase().
indexOf("charset=");
if (charsetPos != -1) {
String encoding = contentType.substring(
charsetPos + "charset=".length()).
toUpperCase();
logger.debug(
"Using streamWriter with encoding : " +
encoding);
streamWriter = new
OutputStreamWriter(outputStream,
encoding);
}
}
streamWriter.write(htmlContent, 0,
htmlContent.length());
streamWriter.flush();
} catch (java.io.IOException ioe) {
logger.error(
"Error writing cache output, IOException generated error",
ioe);
JahiaException outputException = new
JahiaException(
"OperationsManager.handleOperations",
"Error writing cache content to writer",
JahiaException.SECURITY_ERROR,
JahiaException.ERROR_SEVERITY, ioe);
throw new PipelineException(outputException);
}
return; // exit handling here !
}
}
} else {
logger.debug(
"!!!!!! Could not find HTML page in cache!!!!!!!!!!!!!!!!!!");
}
}
if ( (ProcessingContext.CACHE_OFFONCE.equals(processingContext.getCacheStatus())) ||
(ProcessingContext.CACHE_BYPASS.equals(processingContext.getCacheStatus())) ||
(ProcessingContext.CACHE_ONLYUPDATE.equals(processingContext.getCacheStatus()))
) {
// if we have a mode that is only temporary, all the
// urls will be generated to have the cache active
// by default.
processingContext.setCacheStatus(ProcessingContext.CACHE_ON);
}
} else {
logger.debug("Output cache not activated.");
}
valveContext.invokeNext(context);
}
Kind Regards,
Marc
>
From: ghislain.cussonneau [mailto:[email protected]]
Sent: 12 December 2005 15:53
To: template_list
Subject: RE: Publication date
>
>
Ok !
>
>
I've done that and everything goes well ! For your interest, the following codes are the solution I've use (in order templates adding code / patch on jahia / apache conf).
>
>
I've put the new HtmlCacheEntry in webapps/jahia/WEB-INF/classes directory, modify the jahia.properties to add the property "readonlyserver" and restart the server.
>
>
TEMPLATES
>
>
Here is the code I had in header.inc (after the include of declarations.inc) :
>
>
>
Here is the code I had in declarations.inc :
>
>
private static PropertiesManager properties = new PropertiesManager(Jahia.getJahiaPropertiesFileName ());
private boolean bIsReadonlyServer = "true".equals(properties.getProperty("readonlyserver"));
>
public static SimpleDateFormat RFC822DATEFORMAT = new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z", Locale.US);
public static String getDateAsRFC822String(Date date)
{
return RFC822DATEFORMAT.format(date);
}
>
>
>
PATCH JAHIA 4.0.6
>
>
Here is my personnal org.jahia.services.cache.HtmlCacheEntry (in red the code I've had) :
>
>
>
public class HtmlCacheEntry implements Serializable {
>
>
/** the HTML body content. */
private String contentBody = "";
>
>
/** the HTML content type. */
private String contentType = "";
>
>
/** the date of HTMLCacheEntry creation / update **/
private long contentTimestamp = -1;
>
public HtmlCacheEntry (String contentBody) {
init (contentBody, null, new Date().getTime());
}
>
public HtmlCacheEntry (String contentBody, String contentType) {
init (contentBody, contentType, new Date().getTime());
}
>
>
private void init (String contentBody, String contentType, long contentTimestamp) {
if (contentBody != null)
this.contentBody = contentBody;
>
if (contentType != null)
this.contentType = contentType;
this.contentTimestamp = contentTimestamp;
}
>
final public String getContentType() {
return contentType;
}
>
final public void setContentType (String contentType) {
this.contentType = contentType;
this.contentTimestamp = new Date().getTime();
}
>
final public String getContentBody() {
return contentBody;
}
>
final public void setContentBody (String contentBody) {
this.contentBody = contentBody;
this.contentTimestamp = new Date().getTime();
}
>
final public long getContentTimestamp() {
return contentTimestamp;
}
>
}
>
Then in Apache, I've had a new virtual site declaration for my site
>
>
>
ServerName www.mysite.mydomain.fr
>
# Logging access
CustomLog "|/apache/2.0.54/bin/rotatelogs /apache/logs/jahiaconsult_access_mysitekey_log.%Y-%m-%d-%H_%M_%S.log 86400" common
>
# Redirections
Redirect /index.html http://www.mysite.mydomain.fr/jahia/Jahia/site/mysitekey
DocumentRoot /apache/2.0.54/htdocs
>
RewriteEngine On
>
RewriteRule /favicon.ico - [F]
RewriteRule (.*)/op(.*)$ http://www.mysite.mydomain.edit.fr/jahia/Jahia/engineName/login/site/mysitekey
RewriteRule ^/jahia/administration(.*)$ http://www.mysite.mydomain.edit.fr/jahia/administration
>
ProxyPass /jahia/Jahia/op !
ProxyPass /jahia/Jahia/site/mysitekey/op !
ProxyPass /jahia/administration !
ProxyPass /jahia http://www.mysite.mydomain.fr:9080/jahia
ProxyPassReverse /jahia http://www.mysite.mydomain.fr:9080/jahia
>
# Gestion du Cache
CacheRoot "/apache/2.0.54/proxy/www.mysite.mydomain.fr"
CacheSize 50000
CacheEnable disk /
CacheGcInterval 0.25
CacheMaxExpire 180
CacheLastModifiedFactor 0.1
CacheDefaultExpire 0.25
CacheDirLength 2
CacheDirLevels 3
>
# Expire - by request
ExpiresActive On
ExpiresByType image/gif A86400
ExpiresByType image/png A86400
ExpiresByType image/jpeg A86400
ExpiresByType text/css A86400
>
>
>
Regards for your Help.
>
>
>
Ghislain CUSSONNEAU
>
DIRR/DPIL/CIS
>
CAP 44, Rue Marcel Sembat
>
44000 Nantes
>
02 51 84 48 80
>
>
>
>
Accédez au courrier électronique de La Poste : www.laposte.net ;
>
Jusqu'au 25 décembre, participez au grand jeu du Calendrier de l'Avent et
>
gagnez tous les jours de nombreux lots, + de 300 cadeaux en jeu !
Accédez au courrier électronique de La Poste : www.laposte.net ;
Jusqu'au 25 décembre, participez au grand jeu du Calendrier de l'Avent et
gagnez tous les jours de nombreux lots, + de 300 cadeaux en jeu !