OpenHFT/Chronicle map failed

584 Views Asked by At

I am using a VanillaChroncile to temporary store and retrieve entries, and it all works perfectly fine, except when there is huge load. I get the map failed exception. Although I have recovery logic that handles this exception, I would like to know why I am getting the exception in the first place. Any help would be greatly appreciated.

     public enum PreAuthEventChronicle {
INSTANCE;
private String basePath = PropertyUtilsEnum.INSTANCE.getChronicleDirPath();
private final Logger logger = Logger.getLogger(PreAuthEventChronicle.class);
private long indexBlockSize = 64L;
// Length of the excerpt.
private final int excerptLength = 1024;
private final int cycleLength = "yyyyMMddhhmmss";
// Number of entries that are stored in the chronicle queue.
private final long entriesPerCycle = 1L << 20;
// Format for the folder. Chronicle writes in GMT time zone.
private final String format = ApplicationConstants.CHRONICLE_FORMAT;
private Chronicle chronicle = null;
private List<PreAuthEventListener> listeners = new      ArrayList<PreAuthEventListener>();

public Chronicle getChr() {
    return chronicle;
}

/**
 * There can only be one chronicle built.
 */
private PreAuthEventChronicle() {
    if (basePath != null) {
        if (!basePath.endsWith(ApplicationConstants.FILE_SEP)) {
            basePath = basePath + ApplicationConstants.FILE_SEP + ApplicationConstants.CHRONICLE_DATA_PATH;
        }
        logger.debug("Starting from a clean state");
        cleanUp();
        logger.debug("Building a Vanilla Chronicle instance with path: " + basePath);
        buildChronicle();
    } else {
        throw new RuntimeException("No directory specified for chronicle to be built.");
    }
}

private void buildChronicle() {
    logger.debug("Begin-Starting to build a vanilla chronicle");
    try {
        if (chronicle != null) {
            chronicle.clear();
            chronicle = null;
        }
        chronicle = ChronicleQueueBuilder.vanilla(basePath).cycleLength(cycleLength, false).cycleFormat(format)
                .indexBlockSize(indexBlockSize).entriesPerCycle(entriesPerCycle).build();
    } catch (IOException e) {
        logger.error("Error building chronicle" + e.getMessage());
    }
    logger.debug("End-Finished building the vanilla chronicle");
}

/**
 * Clean up the resources
 */
public void cleanUp() {
    logger.debug("Begin-Cleaning up chronicle resources");
    File f = new File(basePath);
    if (f.exists() && f.isDirectory()) {
        File[] dirs = f.listFiles();
        for (File dir : dirs) {
            if (dir.isDirectory()) {
                try {
                    FileUtils.deleteDirectory(dir);
                } catch (IOException ignore) {
                }
            }
        }
    }
    buildChronicle();
    logger.debug("End-Done cleaning up chronicle resources");
}

/**
 * Write the object to the chronicle queue, and notify the listeners
 * 
 * @param event
 * @throws IOException
 */
public synchronized void writeObject(Object event) throws IOException {
    ExcerptAppender appender = INSTANCE.getChr().createAppender();
    if (appender != null && event != null) {
        logger.debug("Begin-Writing event to the chronicle queue");
        appender.startExcerpt(excerptLength);
        appender.writeObject(event);
        appender.finish();
        appender.clear();
        appender.close();
        notifyListeners();
        logger.debug("End-Done writing event to the chronicle queue.");
    }
}

/**
 * Read the object from the queue
 * 
 * @return
 * @throws IOException
 */
public synchronized Object readObject() throws IOException {
    ExcerptTailer reader = INSTANCE.getChr().createTailer().toStart();
    Object evt = null;
    while (reader != null && reader.nextIndex()) {
        logger.debug("Begin-Reading event from the chronicle queue");
        evt = reader.readObject();
        reader.finish();
        reader.clear();
        reader.close();
        logger.debug("End-Done reading the event from the chronicle queue.");
    }
    return evt;
}

/**
 * Attach a listener
 * 
 * @param listen
 */
public void attachListener(PreAuthEventListener listen) {
    listeners.add(listen);
}

/**
 * Notify the listeners that an event has been written.
 */
private void notifyListeners() {
    for (PreAuthEventListener listener : listeners) {
        logger.debug("Notification received from the chronicle queue. Performing action.");
        listener.perform();
    }
}

}

1

There are 1 best solutions below

0
On

It would be useful to know what is the exception you get but I bet the cause is OutOfMemoryError.

About your code:

  • you want to roll every second which is possible but not really efficient as for each roll, Chronicle-Queue needs to mmap at least two regions
  • readObject/writeObject are synchronized methods which is not needed as Va nillaChronicle is thread safe
  • in readObject you close the tailer in each loop which may cause the mapped region to be unmapped/mapped for each iteration, best it to call close() outside the loop
  • in writeObject you explicit close the excerpt which is ok if you do not have control of the number of thread calling that method but it may not be the most efficient way as for each new thread a new region has to be mapped
  • no need to call [tailer|appender].clear()