boolean truncateLogs(boolean force) throws ObjectStoreException { synchronized (_logNames) { Iterator<LogInstance> iter = _logNames.iterator(); /* * Only do this for logs that are full to save time, * except if we are terminating. */ while (iter.hasNext()) { boolean delete = false; LogInstance log = null; try { log = iter.next(); if (log.isFrozen() || force) delete = truncateLog(log, force); } catch (final Exception ex) { // TODO log } if (delete) iter.remove(); } } return true; }
private final void removeFromLog(Uid txid) { if (_synchronousRemoval) { synchronized (_logNames) { Iterator<LogInstance> iter = _logNames.iterator(); LogInstance entry = null; while (iter.hasNext()) { entry = (LogInstance) iter.next(); if (entry.present(txid)) { // entry.removeTxId(txid); break; } } } } }
private final boolean truncateLog(final LogInstance log, boolean force) throws ObjectStoreException { boolean delete = false; synchronized (_lock) { File fd = new File(genPathName(log.getName(), log.getTypeName(), StateStatus.OS_COMMITTED)); try { /* * Create a list of ObjectState entries. */ ArrayList<InputObjectState> objectStates = scanLog(log.getName(), log.getTypeName()); /* * At this stage we should now have a list of unique * entries. Write them back to the log. Do this * atomically! If the list is empty then delete the * file! */ if ((objectStates != null) && (objectStates.size() > 0)) { /* * If we are terminating then we can truncate the log to the * real size needed to contain the existing entries since we * will not use it again within another VM except for * recovery purposes. */ String fname = genPathName(log.getName(), log.getTypeName(), StateStatus.OS_UNCOMMITTED); File fd2 = openAndLock(fname, FileLock.F_WRLCK, true); RandomAccessFile oFile = new RandomAccessFile(fd2, FILE_MODE); int size = 0; oFile.setLength(_maxFileSize); for (int i = 0; i < objectStates.size(); i++) { byte[] uidString = objectStates.get(i).stateUid().stringForm().getBytes(); int buffSize = _redzone.length + uidString.length + objectStates.get(i).buffer().length + 8; java.nio.ByteBuffer buff = java.nio.ByteBuffer.allocate(buffSize); size += buffSize; try { buff.put(_redzone); buff.putInt(uidString.length); buff.put(uidString); buff.putInt(objectStates.get(i).buffer().length); buff.put(objectStates.get(i).buffer(), 0, objectStates.get(i).buffer().length); } catch (final Exception ex) { ex.printStackTrace(); // TODO log fd2.delete(); unlockAndClose(fd2, oFile); throw new ObjectStoreException(ex.toString(), ex); } } try { if (force) { oFile.setLength(size); log.freeze(); } fd2.renameTo(fd); } catch (final Exception ex) { ex.printStackTrace(); // TODO log throw new ObjectStoreException(ex.toString(), ex); } finally { unlockAndClose(fd2, oFile); } } else { /* * Delete the log if there are no states in it. We could * keep the file around and reuse it, but the advantage of * this is small compared to having to cope with reusing old * log instances. */ fd.delete(); /* * Remember to remove the information from the memory cache. */ delete = true; } } catch (final ObjectStoreException ex) { ex.printStackTrace(); throw ex; } catch (final Exception ex) { ex.printStackTrace(); throw new ObjectStoreException(ex.toString(), ex); } } return delete; }
/** * write_state saves the ObjectState in a file named by the type and Uid of the ObjectState. If * the second argument is SHADOW, then the file name is different so that a subsequent * commit_state invocation will rename the file. * * <p>We need to make sure that each entry is written to the next empty location in the log even * if there's already an entry for this tx. */ protected boolean write_state(Uid objUid, String tName, OutputObjectState state, int ft) throws ObjectStoreException { if (tsLogger.logger.isTraceEnabled()) { tsLogger.logger.trace( "ShadowingStore.write_state(" + objUid + ", " + tName + ", " + StateType.stateTypeString(ft) + ")"); } String fname = null; File fd = null; if (tName != null) { int imageSize = (int) state.length(); byte[] uidString = objUid.stringForm().getBytes(); int buffSize = _redzone.length + uidString.length + imageSize + 8; // don't put in endOfLog since we keep overwriting that. RandomAccessFile ofile = null; java.nio.channels.FileLock lock = null; if (imageSize > 0) { TransactionData theLogEntry = getLogName(objUid, tName, buffSize); // always adds entry to log LogInstance theLog = theLogEntry.container; if (theLog == null) throw new ObjectStoreException(); fname = genPathName(theLog.getName(), tName, ft); fd = openAndLock(fname, FileLock.F_WRLCK, true); if (fd == null) { tsLogger.i18NLogger.warn_objectstore_ShadowingStore_18(fname); return false; } boolean setLength = !fd.exists(); try { ofile = new RandomAccessFile(fd, FILE_MODE); if (setLength) { ofile.setLength(_maxFileSize); } else { // may have to resize file if we keep updating this transaction info if (theLog.remaining() < buffSize) { long size = ofile.length() + buffSize - theLog.remaining(); ofile.setLength(size); theLog.resize(size); } } java.nio.ByteBuffer buff = java.nio.ByteBuffer.allocate(buffSize); buff.put(_redzone); buff.putInt(uidString.length); buff.put(uidString); buff.putInt(imageSize); buff.put(state.buffer()); synchronized (_lock) { ofile.seek(theLogEntry.offset); ofile.write(buff.array()); } } catch (SyncFailedException e) { unlockAndClose(fd, ofile); throw new ObjectStoreException( "ShadowingStore::write_state() - write failed to sync for " + fname, e); } catch (FileNotFoundException e) { unlockAndClose(fd, ofile); e.printStackTrace(); throw new ObjectStoreException( "ShadowingStore::write_state() - write failed to locate file " + fname + ": " + e, e); } catch (IOException e) { unlockAndClose(fd, ofile); e.printStackTrace(); throw new ObjectStoreException( "ShadowingStore::write_state() - write failed for " + fname + ": " + e, e); } finally { try { if (lock != null) lock.release(); } catch (IOException ex) { ex.printStackTrace(); } } } if (!unlockAndClose(fd, ofile)) { tsLogger.i18NLogger.warn_objectstore_ShadowingStore_19(fname); } super.addToCache(fname); return true; } else throw new ObjectStoreException( "ShadowStore::write_state - " + tsLogger.i18NLogger.get_objectstore_notypenameuid() + objUid); }
private final TransactionData getLogName(Uid txid, String tName, long size) throws ObjectStoreException { synchronized (_logNames) { Iterator<LogInstance> iter = _logNames.iterator(); LogInstance entry = null; /* * First check to see if the TxId is in an existing log. Always * return the same log instance for the same txid so we can * keep all data in the same location. This may mean that we have * to extend the size of the log over time to accommodate situations * where the log is modified but not deleted for a while, e.g., during * recovery. */ while (iter.hasNext()) { entry = (LogInstance) iter.next(); if (entry.present(txid)) { if (size == -1) // we are reading only return entry.getTxId(txid); else return entry.addTxId(txid, size); } } /* * If we get here then this TxId isn't in one of the * logs we are maintaining currently. So go back through * the list of logs and find one that is small enough * for us to use. The first one with room will do. */ iter = _logNames.iterator(); while (iter.hasNext()) { entry = (LogInstance) iter.next(); if (!entry.isFrozen()) { if (entry.remaining() > size) { return entry.addTxId(txid, size); } else { /* * TODO * * When can we remove the information about this * log from memory? If we do it too soon then it's possible * that delete entries will not go into the right log. If we * leave it too late then the memory footprint increases. Prune * the entry when we prune the log from disk? */ entry.freeze(); } } } // if we get here, then we need to create a new log entry = new LogInstance(tName, _maxFileSize); _logNames.add(entry); return entry.addTxId(txid, size); } }