Talk about RollingFileAppender of rocketmq

  mq

Order

This article mainly studies rocketmq’s RollingFileAppender.

RollingFileAppender

org/apache/rocketmq/logging/inner/LoggingBuilder.java

   public static class RollingFileAppender extends FileAppender {

        protected long maxFileSize = 10 * 1024 * 1024;

        protected int maxBackupIndex = 1;

        private long nextRollover = 0;

        public RollingFileAppender() {
            super();
        }

        public int getMaxBackupIndex() {
            return maxBackupIndex;
        }

        public long getMaximumFileSize() {
            return maxFileSize;
        }

        //......

        public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
            throws IOException {
            super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
            if (append) {
                File f = new File(fileName);
                ((CountingQuietWriter) qw).setCount(f.length());
            }
        }

        public void setMaxBackupIndex(int maxBackups) {
            this.maxBackupIndex = maxBackups;
        }

        public void setMaximumFileSize(long maxFileSize) {
            this.maxFileSize = maxFileSize;
        }

        protected void setQWForFiles(Writer writer) {
            this.qw = new CountingQuietWriter(writer, this);
        }

        protected void subAppend(LoggingEvent event) {
            super.subAppend(event);
            if (fileName != null && qw != null) {
                long size = ((CountingQuietWriter) qw).getCount();
                if (size >= maxFileSize && size >= nextRollover) {
                    rollOver();
                }
            }
        }

        protected class CountingQuietWriter extends QuietWriter {

            protected long count;

            public CountingQuietWriter(Writer writer, Appender appender) {
                super(writer, appender);
            }

            public void write(String string) {
                try {
                    out.write(string);
                    count += string.length();
                } catch (IOException e) {
                    appender.handleError("Write failure.", e, Appender.CODE_WRITE_FAILURE);
                }
            }

            public long getCount() {
                return count;
            }

            public void setCount(long count) {
                this.count = count;
            }

        }
    }
  • The subAppend method is rewritten here. After calling the parent class subAppend method, it is determined whether rollOver is required.
  • MaxFileSize is defined here, that is, the size of a single file, and then the nextRollover index is also defined.
  • This is a countingQuietWriter with a Count in it to accumulate the length of the calculated string.

RollingFileAppender.rollOver

org/apache/rocketmq/logging/inner/LoggingBuilder.java

        public void rollOver() {
            File target;
            File file;

            if (qw != null) {
                long size = ((CountingQuietWriter) qw).getCount();
                SysLogger.debug("rolling over count=" + size);
                nextRollover = size + maxFileSize;
            }
            SysLogger.debug("maxBackupIndex=" + maxBackupIndex);

            boolean renameSucceeded = true;
            if (maxBackupIndex > 0) {
                file = new File(fileName + '.' + maxBackupIndex);
                if (file.exists()) {
                    renameSucceeded = file.delete();
                }

                for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {
                    file = new File(fileName + "." + i);
                    if (file.exists()) {
                        target = new File(fileName + '.' + (i + 1));
                        SysLogger.debug("Renaming file " + file + " to " + target);
                        renameSucceeded = file.renameTo(target);
                    }
                }

                if (renameSucceeded) {
                    target = new File(fileName + "." + 1);

                    this.closeFile(); // keep windows happy.

                    file = new File(fileName);
                    SysLogger.debug("Renaming file " + file + " to " + target);
                    renameSucceeded = file.renameTo(target);

                    if (!renameSucceeded) {
                        try {
                            this.setFile(fileName, true, bufferedIO, bufferSize);
                        } catch (IOException e) {
                            if (e instanceof InterruptedIOException) {
                                Thread.currentThread().interrupt();
                            }
                            SysLogger.error("setFile(" + fileName + ", true) call failed.", e);
                        }
                    }
                }
            }

            if (renameSucceeded) {
                try {
                    this.setFile(fileName, false, bufferedIO, bufferSize);
                    nextRollover = 0;
                } catch (IOException e) {
                    if (e instanceof InterruptedIOException) {
                        Thread.currentThread().interrupt();
                    }
                    SysLogger.error("setFile(" + fileName + ", false) call failed.", e);
                }
            }
        }
  • This method first updates the value of nextRollover, then incrementally renames the file according to maxBackupIndex, and then renames the existing file with the. 1 suffix.
  • After the renaming is successful, setFile related settings are made for the new file, writer is associated, and header is written.

Summary

The RollingFileAppender appends the data every time it appends, and then determines whether the file size limit is exceeded. If the limit is exceeded, the rollOver operation is executed, the existing file is renamed, and then a new file is regenerated. Note that there is no synchronization operation here, so the method called by the outermost layer needs synchronization concurrency control.

doc