org.ehcache.transactions.xa.internal.journal.PersistentJournal Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache-transactions Show documentation
Show all versions of ehcache-transactions Show documentation
The transactions module of Ehcache 3
/*
* Copyright Terracotta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ehcache.transactions.xa.internal.journal;
import org.ehcache.spi.serialization.Serializer;
import org.ehcache.transactions.xa.internal.TransactionId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* A persistent, but not durable {@link Journal} implementation.
* This implementation will persist saved states during close and restore them during open. If close is not called,
* all saved states are lost.
*
* @author Ludovic Orban
*/
public class PersistentJournal extends TransientJournal {
private static final Logger LOGGER = LoggerFactory.getLogger(PersistentJournal.class);
private static final String JOURNAL_FILENAME = "journal.data";
protected static class SerializableEntry implements Serializable {
final XAState state;
final boolean heuristic;
final Collection serializedKeys;
protected SerializableEntry(Entry entry, Serializer keySerializer) {
this.state = entry.state;
this.heuristic = entry.heuristic;
this.serializedKeys = new ArrayList();
for (K key : entry.keys) {
ByteBuffer byteBuffer = keySerializer.serialize(key);
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
this.serializedKeys.add(bytes);
}
}
protected Collection deserializeKeys(Serializer keySerializer) throws ClassNotFoundException {
Collection result = new ArrayList();
for (byte[] serializedKey : serializedKeys) {
K key = keySerializer.read(ByteBuffer.wrap(serializedKey));
result.add(key);
}
return result;
}
}
private final File directory;
private final Serializer keySerializer;
public PersistentJournal(File directory, Serializer keySerializer) {
if (directory == null) {
throw new NullPointerException("directory must not be null");
}
if (keySerializer == null) {
throw new NullPointerException("keySerializer must not be null");
}
this.directory = directory;
this.keySerializer = keySerializer;
}
@Override
public void open() throws IOException {
File file = new File(directory, JOURNAL_FILENAME);
if (file.isFile()) {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
try {
boolean valid = ois.readBoolean();
states.clear();
if (valid) {
Map> readStates = (Map>) ois.readObject();
for (Map.Entry> entry : readStates.entrySet()) {
SerializableEntry value = entry.getValue();
states.put(entry.getKey(), new Entry(value.state, value.heuristic, value.deserializeKeys(keySerializer)));
}
}
} catch (IOException ioe) {
LOGGER.warn("Cannot read XA journal, truncating it", ioe);
} catch (ClassNotFoundException cnfe) {
LOGGER.warn("Cannot deserialize XA journal contents, truncating it", cnfe);
} finally {
ois.close();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
try {
oos.writeObject(false);
} finally {
oos.close();
}
}
}
}
@Override
public void close() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(directory, JOURNAL_FILENAME)));
try {
oos.writeBoolean(true);
Map> toSerialize = new HashMap>();
for (Map.Entry> entry : states.entrySet()) {
TransactionId key = entry.getKey();
Entry value = entry.getValue();
toSerialize.put(key, new SerializableEntry(value, keySerializer));
}
oos.writeObject(toSerialize);
states.clear();
} finally {
oos.close();
}
}
}