001: /*
002: * NEMESIS-FORUM.
003: * Copyright (C) 2002 David Laurent(lithium2@free.fr). All rights reserved.
004: *
005: * Copyright (c) 2000 The Apache Software Foundation. All rights reserved.
006: *
007: * Copyright (C) 2001 Yasna.com. All rights reserved.
008: *
009: * Copyright (C) 2000 CoolServlets.com. All rights reserved.
010: *
011: * NEMESIS-FORUM. is free software; you can redistribute it and/or
012: * modify it under the terms of the Apache Software License, Version 1.1,
013: * or (at your option) any later version.
014: *
015: * NEMESIS-FORUM core framework, NEMESIS-FORUM backoffice, NEMESIS-FORUM frontoffice
016: * application are parts of NEMESIS-FORUM and are distributed under
017: * same terms of licence.
018: *
019: *
020: * NEMESIS-FORUM includes software developed by the Apache Software Foundation (http://www.apache.org/)
021: * and software developed by CoolServlets.com (http://www.coolservlets.com).
022: * and software developed by Yasna.com (http://www.yasna.com).
023: *
024: */
025: package org.nemesis.forum.impl;
026:
027: import org.nemesis.forum.util.cache.Cache;
028: import org.nemesis.forum.util.cache.CacheObject;
029: import org.nemesis.forum.util.cache.Cacheable;
030:
031: /**
032: * Central cache management of all caches.
033: */
034: public class DbCacheManager {
035:
036: public static int USER_CACHE = 0;
037: public static int USER_ID_CACHE = 1;
038: public static int GROUP_CACHE = 2;
039: public static int GROUP_ID_CACHE = 3;
040: public static int FORUM_CACHE = 4;
041: public static int FORUM_ID_CACHE = 5;
042: public static int THREAD_CACHE = 6;
043: public static int MESSAGE_CACHE = 7;
044: public static int USER_PERMS_CACHE = 8;
045:
046: protected Cache[] caches;
047:
048: private boolean cacheEnabled = true;
049:
050: public DbCacheManager() {
051: int MINUTE = 1000 * 60;
052: int HOUR = MINUTE * 60;
053:
054: caches = new Cache[9];
055:
056: //Initialize all cache structures
057: caches[USER_CACHE] = new Cache(256 * 1024, 6 * HOUR);
058: caches[USER_ID_CACHE] = new Cache(128 * 1024, 6 * HOUR);
059: caches[GROUP_CACHE] = new Cache(128 * 1024, 6 * HOUR);
060: caches[GROUP_ID_CACHE] = new Cache(128 * 1024, 6 * HOUR);
061: caches[FORUM_CACHE] = new Cache(128 * 1024, 6 * HOUR);
062: caches[FORUM_ID_CACHE] = new Cache(128 * 1024, 6 * HOUR);
063: caches[THREAD_CACHE] = new Cache(128 * 1024, 6 * HOUR);
064: caches[MESSAGE_CACHE] = new Cache(512 * 1024, 6 * HOUR);
065: //The user permissions cache is a special one. It's actually a Cache
066: //of Cache objects. Each of the cache objects in the main cache
067: //corresponds to a particular forum, and is used to cache the
068: //permissions that a user has for a forum. In order to handle this
069: //requirement, we use a special subclass of Cache.
070: caches[USER_PERMS_CACHE] = new UserPermsCache(256 * 1024,
071: 24 * HOUR);
072: }
073:
074: public Cache getCache(int cacheType) {
075: return caches[cacheType];
076: }
077:
078: public void add(int cacheType, Object key, Cacheable object) {
079: caches[cacheType].add(key, object);
080: }
081:
082: public Cacheable get(int cacheType, Object key) {
083: if (!cacheEnabled) {
084: return null;
085: }
086: return caches[cacheType].get(key);
087: }
088:
089: public void remove(int cacheType, Object key) {
090: caches[cacheType].remove(key);
091: //when cache becomes distributed, we'd send out an expire message
092: //here to all other yazd servers.
093: }
094:
095: public void removeUserPerm(Object userID) {
096: Object[] values = caches[USER_PERMS_CACHE].values().toArray();
097: for (int i = 0; i < values.length; i++) {
098: Cache cache = (Cache) ((CacheObject) values[i]).object;
099: cache.remove(userID);
100: }
101: //when cache becomes distributed, we'd send out an expire message
102: //here to all other yazd servers.
103: }
104:
105: public void removeUserPerm(Object userID, Object forumID) {
106: Cache cache = (Cache) caches[USER_PERMS_CACHE].get(forumID);
107: if (cache != null) {
108: cache.remove(userID);
109: }
110: //when cache becomes distributed, we'd send out an expire message
111: //here to all other yazd servers.
112: }
113:
114: public void clear(int cacheType) {
115: caches[cacheType].clear();
116: //when cache becomes distributed, we'd send out an expire message
117: //here to all other yazd servers.
118: }
119:
120: public boolean isCacheEnabled() {
121: return cacheEnabled;
122: }
123:
124: public void setCacheEnabled(boolean cacheEnabled) {
125: this .cacheEnabled = cacheEnabled;
126: }
127: }
128:
129: /**
130: * Special purpose Cache to hold all of the different user permission cache
131: * objects. The main feature is that new caches are automatically created so
132: * that calling get() never returns null.
133: */
134: class UserPermsCache extends Cache {
135:
136: public UserPermsCache(int size, long expireTime) {
137: super (size, expireTime);
138: }
139:
140: public synchronized Cacheable get(Object key) {
141: Cache subCache = (Cache) super .get(key);
142: if (subCache == null) {
143: //cache has expired, or is not there, so put a new one in there.
144: //Cache objects only need to last as long as a user's session
145: //does. Half an hour is a reasonable amount of time for this.
146: subCache = new Cache(2 * 1024, 30 * 1000 * 60);
147: add(key, subCache);
148: }
149: return subCache;
150: }
151:
152: public synchronized void remove(Object key) {
153: CacheObject cacheObject = (CacheObject) cachedObjectsHash
154: .get(key);
155: //If the object is not in cache, stop trying to remove it.
156: if (cacheObject == null) {
157: return;
158: }
159: //remove from the hash map
160: cachedObjectsHash.remove(key);
161: //remove from the cache order list
162: cacheObject.lastAccessedListNode.remove();
163: cacheObject.ageListNode.remove();
164: //remove references to linked list nodes
165: cacheObject.ageListNode = null;
166: cacheObject.lastAccessedListNode = null;
167: //removed the object, so subtract its size from the total.
168: size -= cacheObject.size;
169:
170: //Finally, clear the sub-cache to make sure memory is released.
171: ((Cache) cacheObject.object).clear();
172: }
173:
174: /**
175: * Returns the current size in bytes of the cache. The base getSize() method
176: * does not work correctly because the sub-caches are empty when we first
177: * add them rather than the normal cache assumption that objects are near
178: * the size that they will always be.
179: *
180: * @return the size of the cache in bytes.
181: */
182: public int getSize() {
183: int size = 0;
184: Object[] values = values().toArray();
185: for (int i = 0; i < values.length; i++) {
186: Cache cache = (Cache) values[i];
187: size += cache.getSize();
188: }
189: return size;
190: }
191: }
|