All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.atomikos.recovery.imp.FileSystemRepository Maven / Gradle / Ivy

package com.atomikos.recovery.imp;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectStreamException;
import java.io.StreamCorruptedException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import com.atomikos.icatch.CoordinatorLogEntry;
import com.atomikos.icatch.provider.ConfigProperties;
import com.atomikos.logging.Logger;
import com.atomikos.logging.LoggerFactory;
import com.atomikos.persistence.imp.LogFileLock;
import com.atomikos.recovery.LogException;
import com.atomikos.recovery.LogReadException;
import com.atomikos.recovery.LogWriteException;
import com.atomikos.recovery.Repository;
import com.atomikos.util.VersionedFile;

public class FileSystemRepository implements
		Repository {

	private static final Logger LOGGER = LoggerFactory
			.createLogger(FileSystemRepository.class);
	private VersionedFile file;
	private FileChannel rwChannel = null;
	private LogFileLock lock_;
	@Override
	public void init(ConfigProperties configProperties) throws LogException {
		String baseDir = configProperties.getLogBaseDir();
		String baseName = configProperties.getLogBaseName();
        lock_ = new LogFileLock(baseDir, baseName);
        lock_.acquireLock();
		file = new VersionedFile(baseDir, baseName, ".log");
		
	}

	private Serializer serializer = new Serializer();

	@Override
	public void put(String id, CoordinatorLogEntry coordinatorLogEntry)
			throws LogWriteException {
		
		try {
			initChannelIfNecessary();
			write(coordinatorLogEntry, true);
		} catch (IOException e) {
			throw new LogWriteException(e);
		}
	}

	private synchronized void initChannelIfNecessary() throws FileNotFoundException {
		if (rwChannel == null) {
			rwChannel = file.openNewVersionForNioWriting();
		}
	}

	private void write(CoordinatorLogEntry coordinatorLogEntry,
			boolean flushImmediately) throws IOException {
		String str = serializer.toJSON(coordinatorLogEntry);
		byte[] buffer = str.getBytes();
		ByteBuffer buff = ByteBuffer.wrap(buffer);
		buff.put(buffer);
		buff.rewind();
		writeToFile(buff, coordinatorLogEntry.shouldSync() && flushImmediately);
	}

	private synchronized void writeToFile(ByteBuffer buff, boolean force)
			throws IOException {
		rwChannel.write(buff);
		if (force) {
			rwChannel.force(false);
		}

	}


	@Override
	public CoordinatorLogEntry get(String coordinatorId) {
		throw new UnsupportedOperationException();
	}

	@Override
	public Collection findAllCommittingCoordinatorLogEntries() {
		throw new UnsupportedOperationException();
	}



	@Override
	public Collection getAllCoordinatorLogEntries()
			throws LogReadException {
		Map coordinatorLogEntries = new HashMap();
		FileInputStream fis = null;
		try {
			String line;
			fis = file.openLastValidVersionForReading();
			InputStreamReader isr = new InputStreamReader(fis);
			BufferedReader br = new BufferedReader(isr);

			while ((line = br.readLine()) != null) {
				CoordinatorLogEntry coordinatorLogEntry = deserialize(line);
				coordinatorLogEntries.put(coordinatorLogEntry.id,
						coordinatorLogEntry);
			}
			br.close();

		} catch (java.io.EOFException unexpectedEOF) {
			LOGGER.logDebug("Unexpected EOF - logfile not closed properly last time?", unexpectedEOF);
			// merely return what was read so far...
		} catch (StreamCorruptedException unexpectedEOF) {
			LOGGER.logDebug("Unexpected EOF - logfile not closed properly last time?", unexpectedEOF);
			// merely return what was read so far...
		} catch (ObjectStreamException unexpectedEOF) {
			LOGGER.logDebug("Unexpected EOF - logfile not closed properly last time?", unexpectedEOF);
			// merely return what was read so far...
		} catch (FileNotFoundException firstStart) {
			// the file could not be opened for reading;
			// merely return the default empty vector
		} catch (Exception e) {
			LOGGER.logWarning("Error in recover", e);
			throw new LogReadException(e);
		} finally {
			closeSilently(fis);
		}

		return coordinatorLogEntries.values();
	}

	private void closeSilently(InputStream fis) {
		try {
			if (fis != null)
				fis.close();
		} catch (IOException io) {
			LOGGER.logWarning("Fail to close logfile after reading - ignoring");
		}
	}

	private Deserializer deserializer = new Deserializer();

	private CoordinatorLogEntry deserialize(String line) {
		return deserializer.fromJSON(line);
	}

	@Override
	public void close() {
		try {
			closeOutput();
		} catch (Exception e) {
			LOGGER.logWarning("Error closing file - ignoring",e);
		} finally {
			lock_.releaseLock();	
		}
		
	}
	protected void closeOutput() throws IllegalStateException {
		try {
			if (file != null) {
				file.close();
			}
		} catch (IOException e) {
			throw new IllegalStateException("Error closing previous output", e);
		}
	}

	@Override
	public synchronized void writeCheckpoint(
			Collection checkpointContent)
			throws LogWriteException {

		try {
			closeOutput();

			rwChannel = file.openNewVersionForNioWriting();
			for (CoordinatorLogEntry coordinatorLogEntry : checkpointContent) {
				write(coordinatorLogEntry, false);
			}
			rwChannel.force(false);
			file.discardBackupVersion();
		} catch (FileNotFoundException firstStart) {
			// the file could not be opened for reading;
			// merely return the default empty vector
		} catch (Exception e) {
			throw new LogWriteException(e);
		}

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy