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

org.ehcache.transactions.xa.internal.journal.PersistentJournal Maven / Gradle / Ivy

There is a newer version: 3.10.8
Show newest version
/*
 * 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) {
          @SuppressWarnings("unchecked")
          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();
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy