001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.server.cluster;
031:
032: import com.caucho.log.Log;
033: import com.caucho.util.Alarm;
034: import com.caucho.vfs.Crc64Stream;
035: import com.caucho.vfs.ReadStream;
036: import com.caucho.vfs.TempStream;
037: import com.caucho.vfs.VfsStream;
038: import com.caucho.vfs.WriteStream;
039:
040: import java.io.IOException;
041: import java.io.InputStream;
042: import java.io.NotSerializableException;
043: import java.io.ObjectInputStream;
044: import java.io.ObjectOutputStream;
045: import java.io.ObjectStreamClass;
046: import java.util.logging.Level;
047: import java.util.logging.Logger;
048:
049: /**
050: * Data for the cluster's object.
051: */
052: public class ClusterObject {
053: private static final Logger log = Log.open(ClusterObject.class);
054:
055: private final StoreManager _storeManager;
056: private final Store _store;
057: private final String _storeId;
058: private final String _objectId;
059:
060: private final String _uniqueId;
061:
062: private ObjectManager _objectManager;
063:
064: private boolean _isPrimary;
065: private long _maxIdleTime;
066:
067: private long _expireInterval = -1;
068:
069: private long _accessTime;
070:
071: private long _crc = -1;
072:
073: private boolean _isSerializable = true;
074: // true if the current data is valid and up to date
075: private boolean _isValid = true;
076: private boolean _isChanged = false;
077: private boolean _isDead = false;
078:
079: ClusterObject(StoreManager storeManager, Store store,
080: String objectId) {
081: _storeManager = storeManager;
082: _objectManager = store.getObjectManager();
083: _store = store;
084: _maxIdleTime = _store.getMaxIdleTime();
085:
086: _storeId = store.getId();
087: _objectId = objectId;
088: _uniqueId = _storeId + ';' + objectId;
089:
090: _isPrimary = isPrimary(_objectId);
091:
092: _expireInterval = getMaxIdleTime() + getAccessWindow();
093: }
094:
095: ClusterObject(StoreManager storeManager, String storeId,
096: String objectId) {
097: _storeManager = storeManager;
098: _objectManager = null;
099: _store = null;
100:
101: _maxIdleTime = _storeManager.getMaxIdleTime();
102:
103: _storeId = storeId;
104: _objectId = objectId;
105: _uniqueId = _storeId + ';' + objectId;
106:
107: _isPrimary = isPrimary(_objectId);
108:
109: _expireInterval = getMaxIdleTime() + getAccessWindow();
110: }
111:
112: public void setObjectManager(ObjectManager objectManager) {
113: _objectManager = objectManager;
114: }
115:
116: // XXX: move to store manager?
117: private boolean isPrimary(String id) {
118: if (_store != null && _store.isAlwaysLoad())
119: return false;
120:
121: else if (_store == null && _storeManager.isAlwaysLoad())
122: return false;
123:
124: return _storeManager.isPrimary(id);
125: }
126:
127: /**
128: * Returns the store.
129: */
130: public Store getStore() {
131: return _store;
132: }
133:
134: /**
135: * Returns the store manager.
136: */
137: public StoreManager getStoreManager() {
138: return _storeManager;
139: }
140:
141: /**
142: * Returns the store id.
143: */
144: public String getStoreId() {
145: return _storeId;
146: }
147:
148: /**
149: * Returns the object id.
150: */
151: public String getObjectId() {
152: return _objectId;
153: }
154:
155: /**
156: * Returns the unique id.
157: */
158: public String getUniqueId() {
159: return _uniqueId;
160: }
161:
162: /**
163: * Returns the max idle time.
164: */
165: public long getMaxIdleTime() {
166: return _maxIdleTime;
167: }
168:
169: /**
170: * Sets the max idle time.
171: */
172: public void setMaxIdleTime(long maxIdleTime) {
173: _maxIdleTime = maxIdleTime;
174: }
175:
176: /**
177: * Returns the access window.
178: */
179: public long getAccessWindow() {
180: long window = _maxIdleTime / 4;
181:
182: if (window < 60000L)
183: return 60000L;
184: else
185: return window;
186: }
187:
188: /**
189: * Sets true for the primary server.
190: */
191: public void setPrimary(boolean primary) {
192: _isPrimary = primary;
193: }
194:
195: /**
196: * Returns the object's saved CRC value.
197: */
198: long getCRC() {
199: return _crc;
200: }
201:
202: /**
203: * Sets the object's saved CRC value.
204: */
205: void setCRC(long crc) {
206: _crc = crc;
207: }
208:
209: /**
210: * Returns true if the object has up-to-date loaded values
211: */
212: boolean isValid() {
213: return _isValid;
214: }
215:
216: /**
217: * Sets the object's saved update count
218: */
219: void setValid(boolean isValid) {
220: _isValid = isValid;
221: }
222:
223: /**
224: * Sets the object's saved update count
225: */
226: public void setValid() {
227: _isValid = true;
228: }
229:
230: /**
231: * Loads the object from the cluster. If the object fails to load,
232: * its contents may be in an inconsistent state.
233: *
234: * @return true on success.
235: */
236: public boolean load(Object obj) {
237: if (!_isSerializable)
238: return true;
239:
240: if (_isDead)
241: throw new IllegalStateException();
242:
243: if (_isPrimary && _isValid)
244: return true;
245:
246: try {
247: if (_storeManager.load(this , obj)) {
248: _isValid = true;
249:
250: return true;
251: } else {
252: _crc = -1;
253: return false;
254: }
255: } catch (Exception e) {
256: log.log(Level.WARNING, e.toString(), e);
257: _crc = -1;
258:
259: return false;
260: } finally {
261: _isChanged = false;
262: }
263: }
264:
265: /**
266: * Loads the object, called from the store.
267: */
268: boolean load(InputStream is, Object obj) throws IOException {
269: VfsStream streamImpl = new VfsStream(is, null);
270:
271: Crc64Stream crcStream = new Crc64Stream(streamImpl);
272:
273: ReadStream crcIs = new ReadStream(crcStream);
274:
275: _objectManager.load(crcIs, obj);
276:
277: _isValid = true;
278: _crc = crcStream.getCRC();
279:
280: crcIs.close();
281:
282: return true;
283: }
284:
285: /**
286: * Signals that the object has been updated externally, i.e.
287: * that the persistent store now has a more current version of
288: * the object's data.
289: */
290: public void update() {
291: _isValid = false;
292: }
293:
294: /**
295: * Signals that the object has been changed by the application, i.e.
296: * that the object needs to be saved to the persistent store.
297: */
298: public void change() {
299: _isChanged = true;
300: }
301:
302: /**
303: * Marks the object as accessed.
304: */
305: public void access() {
306: long now = Alarm.getCurrentTime();
307:
308: if (getAccessWindow() <= now - _accessTime) {
309: try {
310: _storeManager.accessImpl(getUniqueId());
311: } catch (Exception e) {
312: log.log(Level.WARNING, e.toString(), e);
313: }
314:
315: _accessTime = now;
316: }
317: }
318:
319: /**
320: * Sets the access time.
321: */
322: public void setAccessTime(long accessTime) {
323: _accessTime = accessTime;
324: }
325:
326: /**
327: * Sets the max access time.
328: */
329: public long getExpireInterval() {
330: return _expireInterval;
331: }
332:
333: /**
334: * Sets the max access time.
335: */
336: public void setExpireInterval(long expireInterval) {
337: try {
338: _expireInterval = expireInterval;
339:
340: _storeManager.setExpireInterval(getUniqueId(),
341: expireInterval);
342: } catch (Exception e) {
343: log.log(Level.WARNING, e.toString(), e);
344: }
345: }
346:
347: /**
348: * Saves the object to the cluster.
349: */
350: public void store(Object obj) throws IOException {
351: if (!_isSerializable)
352: return;
353:
354: boolean isValid = _isValid;
355:
356: if (!_isPrimary) {
357: _isValid = false;
358: }
359:
360: if (!_isChanged && !_store.isAlwaysSave())
361: return;
362:
363: _isChanged = false;
364:
365: TempStream tempStream = new TempStream();
366:
367: try {
368: Crc64Stream crcStream = new Crc64Stream(tempStream);
369: WriteStream os = new WriteStream(crcStream);
370:
371: _objectManager.store(os, obj);
372:
373: os.close();
374: os = null;
375:
376: long crc = crcStream.getCRC();
377:
378: if (crc == _crc)
379: return;
380:
381: _crc = crc;
382:
383: _storeManager.store(this , tempStream, crc);
384:
385: if (_isPrimary)
386: _isValid = true;
387:
388: _accessTime = Alarm.getCurrentTime();
389: } catch (NotSerializableException e) {
390: log.warning(e.toString());
391: _isSerializable = false;
392: } catch (Exception e) {
393: log.log(Level.WARNING, e.toString(), e);
394:
395: _isValid = false;
396: } finally {
397: tempStream.destroy();
398: }
399: }
400:
401: /**
402: * Writes updated values
403: */
404: public void write(InputStream is) throws IOException {
405: }
406:
407: /**
408: * Reads the current value
409: */
410: public ReadStream openRead() throws IOException {
411: return null;
412: }
413:
414: /**
415: * Removes the object from the cluster.
416: */
417: public void remove() {
418: try {
419: if (_isDead)
420: return;
421: _isDead = true;
422:
423: _storeManager.remove(this );
424: } catch (Throwable e) {
425: log.log(Level.WARNING, e.toString(), e);
426: }
427: }
428:
429: /**
430: * Removes the object from the cluster.
431: */
432: public void removeImpl() {
433: }
434:
435: static class DistributedObjectInputStream extends ObjectInputStream {
436: DistributedObjectInputStream(InputStream is) throws IOException {
437: super (is);
438: }
439:
440: protected Class resolveClass(ObjectStreamClass v)
441: throws IOException, ClassNotFoundException {
442: String name = v.getName();
443:
444: Thread thread = Thread.currentThread();
445: ClassLoader loader = thread.getContextClassLoader();
446:
447: return Class.forName(name, false, loader);
448: }
449: }
450: }
|