package org.cloudname.timber.server.handler.archiver; import org.cloudname.log.archiver.*; import org.cloudname.log.pb.Timber; import java.io.*; import java.util.logging.Level; import java.util.logging.Logger; /** * This class will create a metadata entry for a LogEvent. Metadata entries are held in a * file with the same name as the Slot file, but with a {METADATA_FILE_SUFFIX}. A metadata entry * consists of the logevent's id, write count, start byte offset and end byte offset. * * Get the active MetadataHandler through the getInstance() method. * @author acidmoose */ public class MetadataHandler { private static final int MAX_FILES_OPEN = 5; private static final Logger LOG = Logger.getLogger(MetadataHandler.class.getName()); public static final String DELIMITER = ","; public static final String METADATA_FILE_SUFFIX = "_md"; public static MetadataHandler instance; private final Object lock = new Object(); private File currentSlotFile; private BufferedWriter currentWriter; private final MetadataWriterLruCache<String, BufferedWriter> writerLruCache = new MetadataWriterLruCache<String, BufferedWriter>(MAX_FILES_OPEN); private MetadataHandler() {} /** * Get the instance of the MetadataHandler. * @return */ public static MetadataHandler getInstance() { if (instance == null) { instance = new MetadataHandler(); } return instance; } /** * Writes an acked event id to the metadata file. * @param slotFile the Slot file for the acked event. * @param id the id of the event acked. */ public void writeAck(final File slotFile, final String id) { synchronized (lock) { try { final BufferedWriter writer = getWriter(slotFile); assert(writer != null); writer.write(id); writer.newLine(); writer.flush(); } catch (IOException e) { LOG.log(Level.WARNING, "Unable to write metadata ack entry.", e); } } } /** * Flushes all metadata writers. * @throws IOException */ public void flush() throws IOException { if (currentWriter != null) { currentWriter.flush(); } for (final BufferedWriter writer : writerLruCache.values()) { try { writer.flush(); } catch (IOException e) { throw new ArchiverException("Got IOException while flushing " + writer.toString(), e); } } } /** * Closes all metadata writers. * @throws IOException */ public void close() throws IOException { flush(); if (currentWriter != null) { currentWriter.close(); } for (final BufferedWriter writer : writerLruCache.values()) { try { writer.close(); } catch (IOException e) { throw new ArchiverException("Got IOException while flushing " + writer.toString(), e); } } } private BufferedWriter getWriter(final File slotFile) throws IOException { if (currentSlotFile == null || !currentSlotFile.equals(slotFile)) { final BufferedWriter writer = writerLruCache.get(slotFile.getAbsolutePath() + METADATA_FILE_SUFFIX); if (writer != null) { return writer; } final File mdFile = new File(slotFile.getAbsolutePath() + METADATA_FILE_SUFFIX); if (!mdFile.exists()) { if (! mdFile.getParentFile().exists()) { mdFile.getParentFile().mkdirs(); } mdFile.createNewFile(); } currentSlotFile = slotFile; currentWriter = new BufferedWriter(new FileWriter(mdFile, true)); writerLruCache.put(mdFile.getAbsolutePath(), currentWriter); } return currentWriter; } }