You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by eh...@apache.org on 2007/04/07 02:18:47 UTC

svn commit: r526326 - /incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/wicket/protocol/http/FilePageStore.java

Author: ehillenius
Date: Fri Apr  6 17:18:46 2007
New Revision: 526326

URL: http://svn.apache.org/viewvc?view=rev&rev=526326
Log:
sorted members

Modified:
    incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/wicket/protocol/http/FilePageStore.java

Modified: incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/wicket/protocol/http/FilePageStore.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/wicket/protocol/http/FilePageStore.java?view=diff&rev=526326&r1=526325&r2=526326
==============================================================================
--- incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/wicket/protocol/http/FilePageStore.java (original)
+++ incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/wicket/protocol/http/FilePageStore.java Fri Apr  6 17:18:46 2007
@@ -48,378 +48,224 @@
  */
 public class FilePageStore implements IPageStore
 {
-	/** log. */
-	protected static Log log = LogFactory.getLog(FilePageStore.class);
-
-	private static final Object SERIALIZING = new Object();
-
-	private final File defaultWorkDir;
-
-	private final PageSerializingThread serThread;
-	private final ConcurrentHashMap pagesToBeSerialized;
-
-
-	private final PageSavingThread saveThread;
-	private final ConcurrentHashMap pagesToBeSaved;
-
-
-	private final String appName;
-
-	private volatile int serialized;
-	private volatile long totalSerializationTime = 0;
-
-	/**
-	 * Construct.
-	 */
-	public FilePageStore()
-	{
-		this((File)((WebApplication)Application.get()).getServletContext().getAttribute(
-				"javax.servlet.context.tempdir"));
-	}
-
-	/**
-	 * Construct.
-	 * 
-	 * @param dir
-	 *            The directory to save to.
-	 */
-	public FilePageStore(File dir)
+	private class PageSavingThread implements Runnable
 	{
-		defaultWorkDir = new File(dir, "sessions/");
-		defaultWorkDir.mkdirs();
-
-		pagesToBeSerialized = new ConcurrentHashMap();
-		pagesToBeSaved = new ConcurrentHashMap();
-		appName = Application.get().getApplicationKey();
-
-		saveThread = new PageSavingThread();
-		Thread t = new Thread(saveThread, "FilePageSavingThread-" + appName);
-		t.setDaemon(true);
-		t.setPriority(Thread.MAX_PRIORITY);
-		t.start();
-
-		serThread = new PageSerializingThread();
-		t = new Thread(serThread, "FilePageSerializingThread-" + appName);
-		t.setDaemon(true);
-		t.setPriority(Thread.NORM_PRIORITY);
-		t.start();
-
-		log.info("storing sessions in " + dir + "/sessions");
-	}
+		private volatile boolean stop = false;
+		private long totalSavingTime = 0;
+		private int saved;
+		private int bytesSaved;
 
-	/**
-	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#getPage(java.lang.String,
-	 *      int, int)
-	 */
-	public Page getPage(String sessionId, String pagemapName, int id, int versionNumber,
-			int ajaxVersionNumber)
-	{
-		SessionPageKey currentKey = new SessionPageKey(sessionId, id, versionNumber,
-				ajaxVersionNumber, pagemapName, null);
-		long t = System.currentTimeMillis();
-		byte[] bytes = testMap(currentKey);
-		if (bytes != null)
-		{
-			Page page = (Page)Objects.byteArrayToObject(bytes);
-			page = page.getVersion(versionNumber);
-			return page;
-		}
-		File sessionDir = new File(getWorkDir(), sessionId);
-		if (sessionDir.exists())
+		/**
+		 * @see java.lang.Runnable#run()
+		 */
+		public void run()
 		{
-			File pageFile = getPageFile(currentKey, sessionDir);
-			if (pageFile.exists())
+			while (!stop)
 			{
-				long t1 = System.currentTimeMillis();
-				FileInputStream fis = null;
 				try
 				{
-					byte[] pageData = null;
-					fis = new FileInputStream(pageFile);
-					int length = (int)pageFile.length();
-					ByteBuffer bb = ByteBuffer.allocate(length);
-					fis.getChannel().read(bb);
-					if (bb.hasArray())
-					{
-						pageData = bb.array();
-					}
-					else
-					{
-						pageData = new byte[length];
-						bb.get(pageData);
-					}
-					long t2 = System.currentTimeMillis();
-					Page page = (Page)Objects.byteArrayToObject(pageData);
-					page = page.getVersion(versionNumber);
-					if (page != null && log.isDebugEnabled())
+					while (pagesToBeSaved.size() == 0)
 					{
-						long t3 = System.currentTimeMillis();
-						log.debug("restoring page " + page.getClass() + "[" + page.getNumericId()
-								+ "," + page.getCurrentVersionNumber() + "] size: "
-								+ pageData.length + " for session " + sessionId + " took "
-								+ (t2 - t1) + " miliseconds to read in and " + (t3 - t2)
-								+ " miliseconds to deserialize");
+						Thread.sleep(2000);
+						if (stop)
+							return;
 					}
-					return page;
-				}
-				catch (Exception e)
-				{
-					log.debug("Error loading page " + id + "," + versionNumber
-							+ " for the sessionid " + sessionId + " from disk", e);
-				}
-				finally
-				{
-					try
+					// if ( pagesToBeSaved.size() > 100)
+					// {
+					// System.err.println("max");
+					// Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
+					// }
+					// else if ( pagesToBeSaved.size() > 25)
+					// {
+					// System.err.println("normal");
+					// Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
+					// }
+					// else
+					// {
+					// System.err.println("min");
+					// Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
+					// }
+					Iterator it = pagesToBeSaved.entrySet().iterator();
+					while (it.hasNext())
 					{
-						if (fis != null)
+						Map.Entry entry = (Entry)it.next();
+						SessionPageKey key = (SessionPageKey)entry.getKey();
+						if (key.data instanceof byte[])
 						{
-							fis.close();
+							savePage(key, (byte[])key.data);
 						}
-					}
-					catch (IOException ex)
-					{
-						// ignore
+						it.remove();
 					}
 				}
-			}
-		}
-		return null;
-	}
-
-	/**
-	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#removePage(java.lang.String,
-	 *      wicket.Page)
-	 */
-	public void removePage(String sessionId, Page page)
-	{
-		removePageFromPendingMap(sessionId, page.getNumericId());
-	}
-
-	/**
-	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#storePage(java.lang.String,
-	 *      wicket.Page)
-	 */
-	public void storePage(String sessionId, Page page)
-	{
-		List list = (List)pagesToBeSerialized.get(sessionId);
-		if (list == null)
-		{
-			list = new LinkedList();
-		}
-		synchronized (list)
-		{
-			list.add(new SessionPageKey(sessionId, page));
-		}
-		// do really put it back in.. The writer thread could have removed it.
-		pagesToBeSerialized.put(sessionId, list);
-	}
-
-	/**
-	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#pageAccessed(java.lang.String,
-	 *      wicket.Page)
-	 */
-	public void pageAccessed(String sessionId, Page page)
-	{
-		SessionPageKey currentKey = new SessionPageKey(sessionId, page);
-		testMap(currentKey);
-	}
-
-
-	/**
-	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#destroy()
-	 */
-	public void destroy()
-	{
-		saveThread.stop();
-		serThread.stop();
-	}
-
-	private byte[] testMap(SessionPageKey currentKey)
-	{
-		SessionPageKey previousPage = (SessionPageKey)pagesToBeSaved.get(currentKey);
-		if (previousPage != null)
-		{
-			return (byte[])previousPage.data;
-		}
-		List list = (List)pagesToBeSerialized.get(currentKey.sessionId);
-
-		if (list == null)
-			return null;
-
-		synchronized (list)
-		{
-			int index = list.indexOf(currentKey);
-			if (index != -1)
-			{
-				currentKey = (SessionPageKey)list.get(index);
-				Object object = currentKey.data;
-				if (object instanceof Page)
-				{
-					list.remove(index);
-				}
-				else if (object == SERIALIZING)
+				catch (Exception e)
 				{
-					try
-					{
-						list.wait();
-					}
-					catch (InterruptedException ex)
-					{
-						throw new RuntimeException(ex);
-					}
-					object = currentKey.data;
-					if (object instanceof byte[])
-					{
-						return (byte[])object;
-					}
-					else
-					{
-						previousPage = (SessionPageKey)pagesToBeSaved.get(currentKey);
-						if (previousPage != null)
-						{
-							return (byte[])previousPage.data;
-						}
-						return null;
-					}
-				}
-			}
-			else
-			{
-				return null;
-			}
-		}
-
-		byte[] bytes = serializePage(currentKey, (Page)currentKey.data);
-		if (bytes != null)
-		{
-			currentKey.setObject(bytes);
-			pagesToBeSaved.put(currentKey, currentKey);
-		}
-		return bytes;
-	}
-
-
-	/**
-	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#unbind(java.lang.String)
-	 */
-	public void unbind(String sessionId)
-	{
-		removeSessionFromPendingMap(sessionId);
-	}
+					log.error("Error in page save thread", e);
+				}
+			}
+		}
 
-	private void removeSessionFromPendingMap(String sessionId)
-	{
-		pagesToBeSerialized.remove(sessionId);
-		// TODO remove from pagesToBeSaved..
-		removeSession(sessionId);
+		/**
+		 * Stops this thread.
+		 */
+		public void stop()
+		{
+			if (log.isDebugEnabled())
+			{
+				log.debug("Total time in saving: " + totalSavingTime);
+				log.debug("Bytes saved: " + bytesSaved);
+				log.debug("Pages saved: " + saved);
+			}
+			stop = true;
+		}
 
-	}
 
-	private void removeSession(String sessionId)
-	{
-		File sessionDir = new File(getWorkDir(), sessionId);
-		if (sessionDir.exists())
+		/**
+		 * @param sessionId
+		 * @param key
+		 * @param bytes
+		 */
+		private void savePage(SessionPageKey key, byte[] bytes)
 		{
-			File[] files = sessionDir.listFiles();
-			if (files != null)
+			File sessionDir = new File(getWorkDir(), key.sessionId);
+			sessionDir.mkdirs();
+			File pageFile = getPageFile(key, sessionDir);
+
+			FileOutputStream fos = null;
+			long t1 = System.currentTimeMillis();
+			int length = 0;
+			try
 			{
-				for (int i = 0; i < files.length; i++)
+				fos = new FileOutputStream(pageFile);
+				ByteBuffer bb = ByteBuffer.wrap(bytes);
+				fos.getChannel().write(bb);
+				length = bytes.length;
+			}
+			catch (Exception e)
+			{
+				log.error("Error saving page " + key.pageClass + " [" + key.id + ","
+						+ key.versionNumber + "] for the sessionid " + key.sessionId);
+			}
+			finally
+			{
+				try
 				{
-					files[i].delete();
+					if (fos != null)
+					{
+						fos.close();
+					}
+				}
+				catch (IOException ex)
+				{
+					// ignore
 				}
 			}
-			if (!sessionDir.delete())
+			long t3 = System.currentTimeMillis();
+			if (log.isDebugEnabled())
 			{
-				sessionDir.deleteOnExit();
+				log.debug("storing page " + key.pageClass + "[" + key.id + "," + key.versionNumber
+						+ "] size: " + length + " for session " + key.sessionId + " took "
+						+ (t3 - t1) + " miliseconds to save");
 			}
+			totalSavingTime += (t3 - t1);
+			saved++;
+			bytesSaved += length;
 		}
+
 	}
 
-	/**
-	 * @param sessionId
-	 * @param id
-	 */
-	private void removePageFromPendingMap(String sessionId, int id)
+	private class PageSerializingThread implements Runnable
 	{
-		List list = (List)pagesToBeSerialized.get(sessionId);
+		private volatile boolean stop = false;
 
-		if (list == null)
-			return;
+		private int serializedInThread = 0;
 
-		synchronized (list)
+		/**
+		 * @see java.lang.Runnable#run()
+		 */
+		public void run()
 		{
-			Iterator iterator = list.iterator();
-			while (iterator.hasNext())
+			while (!stop)
 			{
-				SessionPageKey key = (SessionPageKey)iterator.next();
-				if (key.sessionId == sessionId && key.id == id)
+				try
 				{
-					iterator.remove();
-				}
-			}
-		}
-		// TODO remove from pages to be saved
-		removePage(sessionId, id);
-	}
+					while (pagesToBeSerialized.size() == 0)
+					{
+						Thread.sleep(2000);
+						if (stop)
+							return;
+					}
 
+					Iterator it = pagesToBeSerialized.entrySet().iterator();
+					outer : while (it.hasNext())
+					{
+						Map.Entry entry = (Entry)it.next();
+						List sessionList = (List)entry.getValue();
+						while (true)
+						{
+							Page page = null;
+							SessionPageKey key = null;
+							synchronized (sessionList)
+							{
+								if (sessionList.size() != 0)
+								{
+									key = (SessionPageKey)sessionList.get(0);
+									if (key.data instanceof Page)
+									{
+										page = (Page)key.data;
+										key.setObject(SERIALIZING);
+									}
+									else
+									{
+										sessionList.remove(0);
+										System.err.println("shouldn't happen");
+										continue;
+									}
+								}
+								// no key found in the current list.
+								if (key == null)
+								{
+									// the list is removed now!
+									// but it could be that a request add
+									// something to the list now.
+									// thats why a request has to check it
+									// again.
+									pagesToBeSerialized.remove(entry.getKey());
+									continue outer;
+								}
+							}
 
-	private void removePage(String sessionId, int id)
-	{
-		File sessionDir = new File(getWorkDir(), sessionId);
-		if (sessionDir.exists())
-		{
-			final String filepart = appName + "-page-" + id;
-			File[] listFiles = sessionDir.listFiles(new FilenameFilter()
-			{
-				public boolean accept(File dir, String name)
+							byte[] pageBytes = serializePage(key, page);
+							serializedInThread++;
+							synchronized (sessionList)
+							{
+								key.setObject(pageBytes);
+								sessionList.remove(key);
+								sessionList.notifyAll();
+							}
+							pagesToBeSaved.put(key, key);
+						}
+					}
+				}
+				catch (Exception e)
 				{
-					return name.startsWith(filepart);
+					log.error("Error in page save thread", e);
 				}
-			});
-			for (int i = 0; i < listFiles.length; i++)
-			{
-				listFiles[i].delete();
 			}
 		}
 
-	}
-
-	/**
-	 * Returns the working directory for this disk-based PageStore. Override
-	 * this to configure a different location. The default is
-	 * javax.servlet.context.tempdir from the servlet context.
-	 * 
-	 * @return Working directory
-	 */
-	protected File getWorkDir()
-	{
-		return defaultWorkDir;
-	}
-
-	/**
-	 * @param key
-	 * @param sessionDir
-	 * @return The file pointing to the page
-	 */
-	private File getPageFile(SessionPageKey key, File sessionDir)
-	{
-		return new File(sessionDir, appName + "-pm-" + key.pageMap + "-p-" + key.id + "-v-"
-				+ key.versionNumber + "-a-" + key.ajaxVersionNumber);
-	}
-
-	private byte[] serializePage(SessionPageKey key, Page page)
-	{
-		long t1 = System.currentTimeMillis();
-		byte[] bytes = Objects.objectToByteArray(page);
-		totalSerializationTime += (System.currentTimeMillis() - t1);
-		serialized++;
-		if (log.isDebugEnabled())
+		/**
+		 * Stops this thread.
+		 */
+		public void stop()
 		{
-			log.debug("serializing page " + key.pageClass + "[" + key.id + "," + key.versionNumber
-					+ "] size: " + bytes.length + " for session " + key.sessionId + " took "
-					+ (System.currentTimeMillis() - t1) + " miliseconds to serialize");
+			if (log.isDebugEnabled())
+			{
+				log.debug("Total time in serialization: " + totalSerializationTime);
+				log.debug("Total Pages serialized: " + serialized);
+				log.debug("Pages serialized by thread: " + serializedInThread);
+			}
+			stop = true;
 		}
-		return bytes;
 	}
 
 	/**
@@ -436,12 +282,6 @@
 
 		private volatile Object data;
 
-		SessionPageKey(String sessionId, Page page)
-		{
-			this(sessionId, page.getNumericId(), page.getCurrentVersionNumber(), page
-					.getAjaxVersionNumber(), page.getPageMap().getName(), page.getClass(), page);
-		}
-
 		SessionPageKey(String sessionId, int id, int versionNumber, int ajaxVersionNumber,
 				String pagemap, Class pageClass)
 		{
@@ -460,23 +300,35 @@
 			this.data = page;
 		}
 
+		SessionPageKey(String sessionId, Page page)
+		{
+			this(sessionId, page.getNumericId(), page.getCurrentVersionNumber(), page
+					.getAjaxVersionNumber(), page.getPageMap().getName(), page.getClass(), page);
+		}
+
 		/**
-		 * @return The current object inside the SessionPageKey
+		 * @see java.lang.Object#equals(java.lang.Object)
 		 */
-		public Object getObject()
+		public boolean equals(Object obj)
 		{
-			return data;
+			if (obj instanceof SessionPageKey)
+			{
+				SessionPageKey key = (SessionPageKey)obj;
+				return id == key.id
+						&& versionNumber == key.versionNumber
+						&& ajaxVersionNumber == key.ajaxVersionNumber
+						&& ((pageMap != null && pageMap.equals(key.pageMap)) || (pageMap == null && key.pageMap == null))
+						&& sessionId.equals(key.sessionId);
+			}
+			return false;
 		}
 
-		/**
-		 * Sets the current object inside the SessionPageKey
-		 * 
-		 * @param o
-		 *            The object
+		/**
+		 * @return The current object inside the SessionPageKey
 		 */
-		public void setObject(Object o)
+		public Object getObject()
 		{
-			data = o;
+			return data;
 		}
 
 		/**
@@ -488,20 +340,14 @@
 		}
 
 		/**
-		 * @see java.lang.Object#equals(java.lang.Object)
+		 * Sets the current object inside the SessionPageKey
+		 * 
+		 * @param o
+		 *            The object
 		 */
-		public boolean equals(Object obj)
+		public void setObject(Object o)
 		{
-			if (obj instanceof SessionPageKey)
-			{
-				SessionPageKey key = (SessionPageKey)obj;
-				return id == key.id
-						&& versionNumber == key.versionNumber
-						&& ajaxVersionNumber == key.ajaxVersionNumber
-						&& ((pageMap != null && pageMap.equals(key.pageMap)) || (pageMap == null && key.pageMap == null))
-						&& sessionId.equals(key.sessionId);
-			}
-			return false;
+			data = o;
 		}
 
 		/**
@@ -514,223 +360,377 @@
 		}
 	}
 
-	private class PageSavingThread implements Runnable
+	private static final Object SERIALIZING = new Object();
+	/** log. */
+	protected static Log log = LogFactory.getLog(FilePageStore.class);
+
+
+	private final File defaultWorkDir;
+	private final PageSerializingThread serThread;
+
+
+	private final ConcurrentHashMap pagesToBeSerialized;
+
+	private final PageSavingThread saveThread;
+	private final ConcurrentHashMap pagesToBeSaved;
+
+	private final String appName;
+
+	private volatile int serialized;
+
+	private volatile long totalSerializationTime = 0;
+
+	/**
+	 * Construct.
+	 */
+	public FilePageStore()
 	{
-		private volatile boolean stop = false;
-		private long totalSavingTime = 0;
-		private int saved;
-		private int bytesSaved;
+		this((File)((WebApplication)Application.get()).getServletContext().getAttribute(
+				"javax.servlet.context.tempdir"));
+	}
 
-		/**
-		 * Stops this thread.
-		 */
-		public void stop()
+	/**
+	 * Construct.
+	 * 
+	 * @param dir
+	 *            The directory to save to.
+	 */
+	public FilePageStore(File dir)
+	{
+		defaultWorkDir = new File(dir, "sessions/");
+		defaultWorkDir.mkdirs();
+
+		pagesToBeSerialized = new ConcurrentHashMap();
+		pagesToBeSaved = new ConcurrentHashMap();
+		appName = Application.get().getApplicationKey();
+
+		saveThread = new PageSavingThread();
+		Thread t = new Thread(saveThread, "FilePageSavingThread-" + appName);
+		t.setDaemon(true);
+		t.setPriority(Thread.MAX_PRIORITY);
+		t.start();
+
+		serThread = new PageSerializingThread();
+		t = new Thread(serThread, "FilePageSerializingThread-" + appName);
+		t.setDaemon(true);
+		t.setPriority(Thread.NORM_PRIORITY);
+		t.start();
+
+		log.info("storing sessions in " + dir + "/sessions");
+	}
+
+	/**
+	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#destroy()
+	 */
+	public void destroy()
+	{
+		saveThread.stop();
+		serThread.stop();
+	}
+
+
+	/**
+	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#getPage(java.lang.String,
+	 *      int, int)
+	 */
+	public Page getPage(String sessionId, String pagemapName, int id, int versionNumber,
+			int ajaxVersionNumber)
+	{
+		SessionPageKey currentKey = new SessionPageKey(sessionId, id, versionNumber,
+				ajaxVersionNumber, pagemapName, null);
+		long t = System.currentTimeMillis();
+		byte[] bytes = testMap(currentKey);
+		if (bytes != null)
 		{
-			if (log.isDebugEnabled())
-			{
-				log.debug("Total time in saving: " + totalSavingTime);
-				log.debug("Bytes saved: " + bytesSaved);
-				log.debug("Pages saved: " + saved);
-			}
-			stop = true;
+			Page page = (Page)Objects.byteArrayToObject(bytes);
+			page = page.getVersion(versionNumber);
+			return page;
 		}
-
-		/**
-		 * @see java.lang.Runnable#run()
-		 */
-		public void run()
+		File sessionDir = new File(getWorkDir(), sessionId);
+		if (sessionDir.exists())
 		{
-			while (!stop)
+			File pageFile = getPageFile(currentKey, sessionDir);
+			if (pageFile.exists())
 			{
+				long t1 = System.currentTimeMillis();
+				FileInputStream fis = null;
 				try
 				{
-					while (pagesToBeSaved.size() == 0)
+					byte[] pageData = null;
+					fis = new FileInputStream(pageFile);
+					int length = (int)pageFile.length();
+					ByteBuffer bb = ByteBuffer.allocate(length);
+					fis.getChannel().read(bb);
+					if (bb.hasArray())
 					{
-						Thread.sleep(2000);
-						if (stop)
-							return;
+						pageData = bb.array();
 					}
-					// if ( pagesToBeSaved.size() > 100)
-					// {
-					// System.err.println("max");
-					// Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
-					// }
-					// else if ( pagesToBeSaved.size() > 25)
-					// {
-					// System.err.println("normal");
-					// Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
-					// }
-					// else
-					// {
-					// System.err.println("min");
-					// Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
-					// }
-					Iterator it = pagesToBeSaved.entrySet().iterator();
-					while (it.hasNext())
+					else
 					{
-						Map.Entry entry = (Entry)it.next();
-						SessionPageKey key = (SessionPageKey)entry.getKey();
-						if (key.data instanceof byte[])
+						pageData = new byte[length];
+						bb.get(pageData);
+					}
+					long t2 = System.currentTimeMillis();
+					Page page = (Page)Objects.byteArrayToObject(pageData);
+					page = page.getVersion(versionNumber);
+					if (page != null && log.isDebugEnabled())
+					{
+						long t3 = System.currentTimeMillis();
+						log.debug("restoring page " + page.getClass() + "[" + page.getNumericId()
+								+ "," + page.getCurrentVersionNumber() + "] size: "
+								+ pageData.length + " for session " + sessionId + " took "
+								+ (t2 - t1) + " miliseconds to read in and " + (t3 - t2)
+								+ " miliseconds to deserialize");
+					}
+					return page;
+				}
+				catch (Exception e)
+				{
+					log.debug("Error loading page " + id + "," + versionNumber
+							+ " for the sessionid " + sessionId + " from disk", e);
+				}
+				finally
+				{
+					try
+					{
+						if (fis != null)
 						{
-							savePage(key, (byte[])key.data);
+							fis.close();
 						}
-						it.remove();
+					}
+					catch (IOException ex)
+					{
+						// ignore
 					}
 				}
-				catch (Exception e)
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#pageAccessed(java.lang.String,
+	 *      wicket.Page)
+	 */
+	public void pageAccessed(String sessionId, Page page)
+	{
+		SessionPageKey currentKey = new SessionPageKey(sessionId, page);
+		testMap(currentKey);
+	}
+
+
+	/**
+	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#removePage(java.lang.String,
+	 *      wicket.Page)
+	 */
+	public void removePage(String sessionId, Page page)
+	{
+		removePageFromPendingMap(sessionId, page.getNumericId());
+	}
+
+	/**
+	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#storePage(java.lang.String,
+	 *      wicket.Page)
+	 */
+	public void storePage(String sessionId, Page page)
+	{
+		List list = (List)pagesToBeSerialized.get(sessionId);
+		if (list == null)
+		{
+			list = new LinkedList();
+		}
+		synchronized (list)
+		{
+			list.add(new SessionPageKey(sessionId, page));
+		}
+		// do really put it back in.. The writer thread could have removed it.
+		pagesToBeSerialized.put(sessionId, list);
+	}
+
+	/**
+	 * @see wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#unbind(java.lang.String)
+	 */
+	public void unbind(String sessionId)
+	{
+		removeSessionFromPendingMap(sessionId);
+	}
+
+	/**
+	 * @param key
+	 * @param sessionDir
+	 * @return The file pointing to the page
+	 */
+	private File getPageFile(SessionPageKey key, File sessionDir)
+	{
+		return new File(sessionDir, appName + "-pm-" + key.pageMap + "-p-" + key.id + "-v-"
+				+ key.versionNumber + "-a-" + key.ajaxVersionNumber);
+	}
+
+
+	private void removePage(String sessionId, int id)
+	{
+		File sessionDir = new File(getWorkDir(), sessionId);
+		if (sessionDir.exists())
+		{
+			final String filepart = appName + "-page-" + id;
+			File[] listFiles = sessionDir.listFiles(new FilenameFilter()
+			{
+				public boolean accept(File dir, String name)
 				{
-					log.error("Error in page save thread", e);
+					return name.startsWith(filepart);
 				}
+			});
+			for (int i = 0; i < listFiles.length; i++)
+			{
+				listFiles[i].delete();
 			}
 		}
 
+	}
 
-		/**
-		 * @param sessionId
-		 * @param key
-		 * @param bytes
-		 */
-		private void savePage(SessionPageKey key, byte[] bytes)
-		{
-			File sessionDir = new File(getWorkDir(), key.sessionId);
-			sessionDir.mkdirs();
-			File pageFile = getPageFile(key, sessionDir);
+	/**
+	 * @param sessionId
+	 * @param id
+	 */
+	private void removePageFromPendingMap(String sessionId, int id)
+	{
+		List list = (List)pagesToBeSerialized.get(sessionId);
 
-			FileOutputStream fos = null;
-			long t1 = System.currentTimeMillis();
-			int length = 0;
-			try
-			{
-				fos = new FileOutputStream(pageFile);
-				ByteBuffer bb = ByteBuffer.wrap(bytes);
-				fos.getChannel().write(bb);
-				length = bytes.length;
-			}
-			catch (Exception e)
-			{
-				log.error("Error saving page " + key.pageClass + " [" + key.id + ","
-						+ key.versionNumber + "] for the sessionid " + key.sessionId);
-			}
-			finally
+		if (list == null)
+			return;
+
+		synchronized (list)
+		{
+			Iterator iterator = list.iterator();
+			while (iterator.hasNext())
 			{
-				try
+				SessionPageKey key = (SessionPageKey)iterator.next();
+				if (key.sessionId == sessionId && key.id == id)
 				{
-					if (fos != null)
-					{
-						fos.close();
-					}
+					iterator.remove();
 				}
-				catch (IOException ex)
+			}
+		}
+		// TODO remove from pages to be saved
+		removePage(sessionId, id);
+	}
+
+	private void removeSession(String sessionId)
+	{
+		File sessionDir = new File(getWorkDir(), sessionId);
+		if (sessionDir.exists())
+		{
+			File[] files = sessionDir.listFiles();
+			if (files != null)
+			{
+				for (int i = 0; i < files.length; i++)
 				{
-					// ignore
+					files[i].delete();
 				}
 			}
-			long t3 = System.currentTimeMillis();
-			if (log.isDebugEnabled())
+			if (!sessionDir.delete())
 			{
-				log.debug("storing page " + key.pageClass + "[" + key.id + "," + key.versionNumber
-						+ "] size: " + length + " for session " + key.sessionId + " took "
-						+ (t3 - t1) + " miliseconds to save");
+				sessionDir.deleteOnExit();
 			}
-			totalSavingTime += (t3 - t1);
-			saved++;
-			bytesSaved += length;
 		}
-
 	}
 
-	private class PageSerializingThread implements Runnable
+	private void removeSessionFromPendingMap(String sessionId)
 	{
-		private volatile boolean stop = false;
+		pagesToBeSerialized.remove(sessionId);
+		// TODO remove from pagesToBeSaved..
+		removeSession(sessionId);
 
-		private int serializedInThread = 0;
+	}
 
-		/**
-		 * Stops this thread.
-		 */
-		public void stop()
+	private byte[] serializePage(SessionPageKey key, Page page)
+	{
+		long t1 = System.currentTimeMillis();
+		byte[] bytes = Objects.objectToByteArray(page);
+		totalSerializationTime += (System.currentTimeMillis() - t1);
+		serialized++;
+		if (log.isDebugEnabled())
 		{
-			if (log.isDebugEnabled())
-			{
-				log.debug("Total time in serialization: " + totalSerializationTime);
-				log.debug("Total Pages serialized: " + serialized);
-				log.debug("Pages serialized by thread: " + serializedInThread);
-			}
-			stop = true;
+			log.debug("serializing page " + key.pageClass + "[" + key.id + "," + key.versionNumber
+					+ "] size: " + bytes.length + " for session " + key.sessionId + " took "
+					+ (System.currentTimeMillis() - t1) + " miliseconds to serialize");
 		}
+		return bytes;
+	}
 
-		/**
-		 * @see java.lang.Runnable#run()
-		 */
-		public void run()
+	private byte[] testMap(SessionPageKey currentKey)
+	{
+		SessionPageKey previousPage = (SessionPageKey)pagesToBeSaved.get(currentKey);
+		if (previousPage != null)
 		{
-			while (!stop)
+			return (byte[])previousPage.data;
+		}
+		List list = (List)pagesToBeSerialized.get(currentKey.sessionId);
+
+		if (list == null)
+			return null;
+
+		synchronized (list)
+		{
+			int index = list.indexOf(currentKey);
+			if (index != -1)
 			{
-				try
+				currentKey = (SessionPageKey)list.get(index);
+				Object object = currentKey.data;
+				if (object instanceof Page)
 				{
-					while (pagesToBeSerialized.size() == 0)
+					list.remove(index);
+				}
+				else if (object == SERIALIZING)
+				{
+					try
 					{
-						Thread.sleep(2000);
-						if (stop)
-							return;
+						list.wait();
 					}
-
-					Iterator it = pagesToBeSerialized.entrySet().iterator();
-					outer : while (it.hasNext())
+					catch (InterruptedException ex)
 					{
-						Map.Entry entry = (Entry)it.next();
-						List sessionList = (List)entry.getValue();
-						while (true)
+						throw new RuntimeException(ex);
+					}
+					object = currentKey.data;
+					if (object instanceof byte[])
+					{
+						return (byte[])object;
+					}
+					else
+					{
+						previousPage = (SessionPageKey)pagesToBeSaved.get(currentKey);
+						if (previousPage != null)
 						{
-							Page page = null;
-							SessionPageKey key = null;
-							synchronized (sessionList)
-							{
-								if (sessionList.size() != 0)
-								{
-									key = (SessionPageKey)sessionList.get(0);
-									if (key.data instanceof Page)
-									{
-										page = (Page)key.data;
-										key.setObject(SERIALIZING);
-									}
-									else
-									{
-										sessionList.remove(0);
-										System.err.println("shouldn't happen");
-										continue;
-									}
-								}
-								// no key found in the current list.
-								if (key == null)
-								{
-									// the list is removed now!
-									// but it could be that a request add
-									// something to the list now.
-									// thats why a request has to check it
-									// again.
-									pagesToBeSerialized.remove(entry.getKey());
-									continue outer;
-								}
-							}
-
-							byte[] pageBytes = serializePage(key, page);
-							serializedInThread++;
-							synchronized (sessionList)
-							{
-								key.setObject(pageBytes);
-								sessionList.remove(key);
-								sessionList.notifyAll();
-							}
-							pagesToBeSaved.put(key, key);
+							return (byte[])previousPage.data;
 						}
+						return null;
 					}
 				}
-				catch (Exception e)
-				{
-					log.error("Error in page save thread", e);
-				}
 			}
+			else
+			{
+				return null;
+			}
+		}
+
+		byte[] bytes = serializePage(currentKey, (Page)currentKey.data);
+		if (bytes != null)
+		{
+			currentKey.setObject(bytes);
+			pagesToBeSaved.put(currentKey, currentKey);
 		}
+		return bytes;
+	}
+
+	/**
+	 * Returns the working directory for this disk-based PageStore. Override
+	 * this to configure a different location. The default is
+	 * javax.servlet.context.tempdir from the servlet context.
+	 * 
+	 * @return Working directory
+	 */
+	protected File getWorkDir()
+	{
+		return defaultWorkDir;
 	}
 }