Return-Path: X-Original-To: apmail-logging-log4j-dev-archive@www.apache.org Delivered-To: apmail-logging-log4j-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 68E9F10A6B for ; Mon, 23 Dec 2013 19:07:51 +0000 (UTC) Received: (qmail 59032 invoked by uid 500); 23 Dec 2013 19:07:51 -0000 Delivered-To: apmail-logging-log4j-dev-archive@logging.apache.org Received: (qmail 58952 invoked by uid 500); 23 Dec 2013 19:07:51 -0000 Mailing-List: contact log4j-dev-help@logging.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Help: List-Post: List-Id: "Log4J Developers List" Reply-To: "Log4J Developers List" Delivered-To: mailing list log4j-dev@logging.apache.org Received: (qmail 58873 invoked by uid 99); 23 Dec 2013 19:07:50 -0000 Received: from arcas.apache.org (HELO arcas.apache.org) (140.211.11.28) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 23 Dec 2013 19:07:50 +0000 Date: Mon, 23 Dec 2013 19:07:50 +0000 (UTC) From: "Claude Mamo (JIRA)" To: log4j-dev@logging.apache.org Message-ID: In-Reply-To: References: Subject: [jira] [Commented] (LOG4J2-431) Create MemoryMappedFileAppender MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-JIRA-FingerPrint: 30527f35849b9dde25b450d4833f0394 [ https://issues.apache.org/jira/browse/LOG4J2-431?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13855857#comment-13855857 ] Claude Mamo commented on LOG4J2-431: ------------------------------------ Hi Remko, I reviewed the cases you mentioned and these should be covered: {code:title=MemoryMappedFileManager.java|borderStyle=solid} protected synchronized void write(final byte[] bytes, int offset, int length) { int chunk = 0; try { do { // re-map if no room is left in buffer if (length > mappedFile.remaining() && chunk != 0) { fileSize = randomAccessFile.length(); mappedFile = randomAccessFile.getChannel().map(FileChannel.MapMode.READ_WRITE, randomAccessFile.length(), mapSize); } chunk = Math.min(length, mappedFile.remaining()); mappedFile.put(bytes, offset, chunk); offset += chunk; length -= chunk; } while (length > 0); } catch (final Exception ex) { LOGGER.error("RandomAccessFileManager (" + getName() + ") " + ex); } } {code} I found a minor bug where unnecessary re-mapping is performed on the first log entry if the write is larger than the map size. I attached an updated version of the MemoryMappedFileManager. > Create MemoryMappedFileAppender > ------------------------------- > > Key: LOG4J2-431 > URL: https://issues.apache.org/jira/browse/LOG4J2-431 > Project: Log4j 2 > Issue Type: New Feature > Components: Appenders > Reporter: Remko Popma > Priority: Minor > Attachments: MemoryMappedFileAppender.java, MemoryMappedFileAppenderTest.java, MemoryMappedFileAppenderTest.xml, MemoryMappedFileManager.java, MemoryMappedFileManagerTest.java > > > A memory-mapped file appender may have better performance than the ByteBuffer + RandomAccessFile combination used by the RandomAccessFileAppender. > *Drawbacks* > * The drawback is that the file needs to be pre-allocated and only up to the file size can be mapped into memory. When the end of the file is reached the appender would need to extend the file and re-map. > * Remapping is expensive (I think single-digit millisecond-range, need to check). For low-latency apps this kind of spike may be unacceptable so careful tuning is required. > * Memory usage: If re-mapping happens too often you lose the performance benefits, so the memory-mapped buffer needs to be fairly large, which uses up memory. > * At roll-over and shutdown the file should be truncated to immediately after the last written data (otherwise the user is left with a log file that ends in garbage). > *Advantages* > Measuring on a Solaris box, the difference between flushing to disk (with {{RandomAccessFile.write(bytes[])}}) and putting data in a MappedByteBuffer is about 20x: around 600ns for a ByteBuffer put and around 12-15 microseconds for a RandomAccessFile.write. > (Of course different hardware and OS may give different results...) > *Use cases* > The difference may be most visible if {{immediateFlush}} is set to {{true}}, which is only recommended if async loggers/appenders are not used. If {{immediateFlush=false}}, the large buffer used by RandomAccessFileAppender means you won't need to touch disk very often. > So a MemoryMappedFileAppender is most useful in _synchronous_ logging scenarios, where you get the speed of writing to memory but the data is available on disk almost immediately. (MMap writes directly to the OS disk buffer.) > In case of a application crash, the OS ensures that all data in the buffer will be written to disk. In case of an OS crash the data that was most recently added to the buffer may not be written to disk. > Because by nature this appender would occupy a fair amount of memory, it is most suitable for applications running on server-class hardware with lots of memory available. -- This message was sent by Atlassian JIRA (v6.1.5#6160) --------------------------------------------------------------------- To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org For additional commands, e-mail: log4j-dev-help@logging.apache.org