Question

I am using VanillaChronicle to write some messages to the disk.

public final class ConcurrentPersister{

    private final String location;
    private final Chronicle chronicle;
    private final ExcerptAppender writer;

    private final static int STRING_SIZE_OVERHEAD   = 1000;
    private final static String FILE_DATE_FORMAT    = "MM-dd-yyyy";
    private final static String NAME                = "ConcurrentPersister";
    private final static Logger LOGGER              = LoggerFactory.getLogger( NAME );



    public ConcurrentPersister( String location, VanillaChronicleConfig config ){
        this.chronicle      = new VanillaChronicle( location );
        this.writer         = chronicle.createAppender();
    }


   public final void appendMessage( final String message ){

        try{

            long length  =  STRING_SIZE_OVERHEAD + message.length();

            writer.startExcerpt( length );
            writer.append( message );
            writer.finish();

        }catch( Exception e ){
            LOGGER.warn("Failed to persist Message [{}]", message );
            LOGGER.warn("Exception: ", e );
        }

    }

}

Is the appendMessage(String message) method, as shown above, thread-safe if called from multiple threads?

I read somewhere that VanillaChronicle's append(String message) is thread-safe. However, am I correct in thinking that the compound action of startExcerpt() + append() + finish() is NOT thread-safe?

Thanks.

Was it helpful?

Solution

VanillaChronicle has a ThreadLocal cache of appenders/tailers:

public VanillaAppender createAppender() throws IOException {
    WeakReference<VanillaAppender> ref = appenderCache.get();
    VanillaAppender appender = null;
    if (ref != null)
        appender = ref.get();
    if (appender == null) {
        appender = createAppender0();
        appenderCache.set(new WeakReference<VanillaAppender>(appender));
    }
    return appender;
}

If you do not have thousand short living threads you can use createAppender in your appendMessage method

public final void appendMessage( final String message ) {
    try {
        ExcerptAppender writer = chronicle.createAppender();
        writer.startExcerpt( STRING_SIZE_OVERHEAD + message.length() );
        writer.append( message );
        writer.finish();
    } catch( Exception e ) {
        LOGGER.warn("Failed to persist Message [{}]", message );
        LOGGER.warn("Exception: ", e );
    }
}

I read somewhere that VanillaChronicle's append(String message) is thread-safe. However, am I correct in thinking that the compound action of startExcerpt() + append() + finish() is NOT thread-safe?

VanillaChronicle can be used by concurrent thread, even concurrent processes, provided each thread uses it's own appender.

OTHER TIPS

You need to synchronise the writer on those three method calls. append( message ); might be thread safe but, as you say, the three separate method calls to writer could clash if multiple threads access the method through the same instance of ConcurrentPersister.

public final class ConcurrentPersister{

    private final String location;
    private final Chronicle chronicle;
    private final ExcerptAppender writer;

    private final static int STRING_SIZE_OVERHEAD   = 1000;
    private final static String FILE_DATE_FORMAT    = "MM-dd-yyyy";
    private final static String NAME                = "ConcurrentPersister";
    private final static Logger LOGGER              = LoggerFactory.getLogger( NAME );



    public ConcurrentPersister( String location, VanillaChronicleConfig config ){
        this.chronicle      = new VanillaChronicle( location );
        this.writer         = chronicle.createAppender();
    }


   public final void appendMessage( final String message ){

        try{

            long length  =  STRING_SIZE_OVERHEAD + message.length();

            synchronized(writer){
                writer.startExcerpt( length );
                writer.append( message );
                writer.finish();
               }

        }catch( Exception e ){
            LOGGER.warn("Failed to persist Message [{}]", message );
            LOGGER.warn("Exception: ", e );
        }

    }

}

Depending on what else you do with this class it might be easier to synchronise the whole method.

   public synchronized final void appendMessage( final String message ){

But this would synchronise on the instance of ConcurrentPersister, not the writer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top