Author: tschoening
Date: Sun Feb  9 18:26:33 2014
New Revision: 1566343

URL: http://svn.apache.org/r1566343
Log:
LOGCXX-412: Log4cxx doesn't roll normally when working under multiple processes 
environment

Modified:
    incubator/log4cxx/trunk/src/changes/changes.xml
    incubator/log4cxx/trunk/src/main/cpp/fixedwindowrollingpolicy.cpp
    incubator/log4cxx/trunk/src/main/cpp/outputstream.cpp
    incubator/log4cxx/trunk/src/main/cpp/outputstreamwriter.cpp
    incubator/log4cxx/trunk/src/main/cpp/rollingfileappender.cpp
    incubator/log4cxx/trunk/src/main/cpp/timebasedrollingpolicy.cpp
    incubator/log4cxx/trunk/src/main/cpp/writer.cpp
    incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/fileoutputstream.h
    incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstream.h
    
incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstreamwriter.h
    incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/writer.h
    
incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h
    incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingpolicybase.h
    
incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/timebasedrollingpolicy.h
    incubator/log4cxx/trunk/src/main/include/log4cxx/writerappender.h

Modified: incubator/log4cxx/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/changes/changes.xml?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- incubator/log4cxx/trunk/src/changes/changes.xml (original)
+++ incubator/log4cxx/trunk/src/changes/changes.xml Sun Feb  9 18:26:33 2014
@@ -62,6 +62,7 @@
                        <action issue="LOGCXX-367" type="fix">Build fails on 
Linux with g++ 4.4</action>
                        <action issue="LOGCXX-381" type="fix">Pkgconfig can't 
find dependencies properly if log4cxx built statically</action>
                        <action issue="LOGCXX-382" type="fix">Mingw build type 
conversion error</action>
+                       <action issue="LOGCXX-412" type="fix">Log4cxx doesn't 
roll normally when working under multiple processes environment</action>
                        <action issue="LOGCXX-413" type="fix">log4cxx doesn't 
compile on openembedded (due to Alex Zbarcea)</action>
                        <action issue="LOGCXX-414" type="fix">possibly wrong 
use of autotools docdir (due to Alex Zbarcea)</action>
                        <action issue="LOGCXX-415" type="fix">Empty XML 
configuration file causes crash</action>

Modified: incubator/log4cxx/trunk/src/main/cpp/fixedwindowrollingpolicy.cpp
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/fixedwindowrollingpolicy.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- incubator/log4cxx/trunk/src/main/cpp/fixedwindowrollingpolicy.cpp (original)
+++ incubator/log4cxx/trunk/src/main/cpp/fixedwindowrollingpolicy.cpp Sun Feb  
9 18:26:33 2014
@@ -160,8 +160,13 @@ RolloverDescriptionPtr FixedWindowRollin
       new FileRenameAction(
         File().setPath(currentFileName), File().setPath(renameTo), false);
 
+#ifdef LOG4CXX_MULTI_PROCESS
+    desc = new RolloverDescription(
+      currentFileName, true, renameAction, compressAction);
+#else
     desc = new RolloverDescription(
       currentFileName, false, renameAction, compressAction);
+#endif
   }
 
   return desc;

Modified: incubator/log4cxx/trunk/src/main/cpp/outputstream.cpp
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/outputstream.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- incubator/log4cxx/trunk/src/main/cpp/outputstream.cpp (original)
+++ incubator/log4cxx/trunk/src/main/cpp/outputstream.cpp Sun Feb  9 18:26:33 
2014
@@ -17,6 +17,7 @@
 
 #include <log4cxx/logstring.h>
 #include <log4cxx/helpers/outputstream.h>
+#include <stdexcept>
 
 using namespace log4cxx;
 using namespace log4cxx::helpers;
@@ -28,3 +29,13 @@ OutputStream::OutputStream() {
 
 OutputStream::~OutputStream() {
 }
+
+#ifdef LOG4CXX_MULTI_PROCESS
+apr_file_t* OutputStream::getFilePtr(){
+    throw std::logic_error("getFilePtr must be implemented in the derived 
class that you are using");
+}
+
+OutputStream& OutputStream::getFileOutPutStreamPtr(){
+    throw std::logic_error("getFileOutPutStreamPtr must be implemented in the 
derived class that you are using");
+}
+#endif

Modified: incubator/log4cxx/trunk/src/main/cpp/outputstreamwriter.cpp
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/outputstreamwriter.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- incubator/log4cxx/trunk/src/main/cpp/outputstreamwriter.cpp (original)
+++ incubator/log4cxx/trunk/src/main/cpp/outputstreamwriter.cpp Sun Feb  9 
18:26:33 2014
@@ -58,9 +58,15 @@ void OutputStreamWriter::flush(Pool& p) 
 
 void OutputStreamWriter::write(const LogString& str, Pool& p) {
   if (str.length() > 0) {
+#ifdef LOG4CXX_MULTI_PROCESS
+    size_t bufSize = str.length() * 2;
+    char *rawbuf = new char[bufSize];
+    ByteBuffer buf(rawbuf, (size_t) bufSize);
+#else
     enum { BUFSIZE = 1024 };
     char rawbuf[BUFSIZE];
     ByteBuffer buf(rawbuf, (size_t) BUFSIZE);
+#endif
     enc->reset();
     LogString::const_iterator iter = str.begin();
     while(iter != str.end()) {
@@ -69,10 +75,14 @@ void OutputStreamWriter::write(const Log
       out->write(buf, p);
       buf.clear();
     }
+
     CharsetEncoder::encode(enc, str, iter, buf);
     enc->flush(buf);
     buf.flip();
     out->write(buf, p);
+#ifdef LOG4CXX_MULTI_PROCESS
+    delete []rawbuf;
+#endif
   }
 }
 

Modified: incubator/log4cxx/trunk/src/main/cpp/rollingfileappender.cpp
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/rollingfileappender.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- incubator/log4cxx/trunk/src/main/cpp/rollingfileappender.cpp (original)
+++ incubator/log4cxx/trunk/src/main/cpp/rollingfileappender.cpp Sun Feb  9 
18:26:33 2014
@@ -19,6 +19,19 @@
 #pragma warning ( disable: 4231 4251 4275 4786 )
 #endif
 
+#ifdef LOG4CXX_MULTI_PROCESS
+#include <apr_portable.h>
+#include <libgen.h>
+#include <apr_file_io.h>
+#include <apr_atomic.h>
+#include <apr_mmap.h>
+#ifndef MAX_FILE_LEN
+#define MAX_FILE_LEN 2048
+#endif
+#include <log4cxx/pattern/filedatepatternconverter.h>
+#include <log4cxx/helpers/date.h>
+#endif
+
 #include <log4cxx/rolling/rollingfileappender.h>
 #include <log4cxx/helpers/loglog.h>
 #include <log4cxx/helpers/synchronized.h>
@@ -41,7 +54,7 @@ IMPLEMENT_LOG4CXX_OBJECT(RollingFileAppe
 /**
  * Construct a new instance.
  */
-RollingFileAppenderSkeleton::RollingFileAppenderSkeleton() {
+RollingFileAppenderSkeleton::RollingFileAppenderSkeleton() : _event(NULL){
 }
 
 RollingFileAppender::RollingFileAppender() {
@@ -115,9 +128,20 @@ void RollingFileAppenderSkeleton::activa
              + getName());
     }
   }
-
 }
 
+#ifdef LOG4CXX_MULTI_PROCESS
+void RollingFileAppenderSkeleton::releaseFileLock(apr_file_t* lock_file){
+    if (lock_file){
+        apr_status_t stat = apr_file_unlock(lock_file);
+        if (stat != APR_SUCCESS){
+            LogLog::warn(LOG4CXX_STR("flock: unlock failed"));
+        }
+        apr_file_close(lock_file);
+        lock_file = NULL;
+    }
+}
+#endif
 /**
    Implements the usual roll over behaviour.
 
@@ -134,105 +158,196 @@ void RollingFileAppenderSkeleton::activa
  * @return true if rollover performed.
  */
 bool RollingFileAppenderSkeleton::rollover(Pool& p) {
-  //
-  //   can't roll without a policy
-  //
-  if (rollingPolicy != NULL) {
+    //
+    //   can't roll without a policy
+    //
+    if (rollingPolicy != NULL) {
+
+        {
+            synchronized sync(mutex);
 
-{
-    synchronized sync(mutex);
-      try {
-        RolloverDescriptionPtr rollover1(rollingPolicy->rollover(getFile(), 
p));
-
-        if (rollover1 != NULL) {
-          if (rollover1->getActiveFileName() == getFile()) {
-            closeWriter();
-
-            bool success = true;
-
-            if (rollover1->getSynchronous() != NULL) {
-              success = false;
-
-              try {
-                success = rollover1->getSynchronous()->execute(p);
-              } catch (std::exception& ex) {
-                LogLog::warn(LOG4CXX_STR("Exception on rollover"));
-              }
+#ifdef LOG4CXX_MULTI_PROCESS
+            std::string fileName(getFile());
+            RollingPolicyBase *basePolicy = dynamic_cast<RollingPolicyBase* 
>(&(*rollingPolicy)); 
+            apr_time_t n = apr_time_now();
+            ObjectPtr obj(new Date(n));
+            LogString fileNamePattern;
+            if (basePolicy){
+                if (basePolicy->getPatternConverterList().size()){
+                    
(*(basePolicy->getPatternConverterList().begin()))->format(obj, 
fileNamePattern, p);
+                    fileName = std::string(fileNamePattern);
+                }
             }
 
-            if (success) {
-              if (rollover1->getAppend()) {
-                fileLength = 
File().setPath(rollover1->getActiveFileName()).length(p);
-              } else {
-                fileLength = 0;
-              }
-
-              //
-              //  async action not yet implemented
-              //
-              ActionPtr asyncAction(rollover1->getAsynchronous());
-              if (asyncAction != NULL) {
-                asyncAction->execute(p);
-              }
-
-              setFile(
-                rollover1->getActiveFileName(), rollover1->getAppend(),
-                bufferedIO, bufferSize, p);
-            } else {
-              setFile(
-                rollover1->getActiveFileName(), true, bufferedIO, bufferSize, 
p);
+            bool bAlreadyRolled = true;
+            char szDirName[MAX_FILE_LEN] = {'\0'};
+            char szBaseName[MAX_FILE_LEN] = {'\0'};
+            char szUid[MAX_FILE_LEN] = {'\0'};
+            memcpy(szDirName, fileName.c_str(), fileName.size() > MAX_FILE_LEN 
? MAX_FILE_LEN : fileName.size());
+            memcpy(szBaseName, fileName.c_str(), fileName.size() > 
MAX_FILE_LEN ? MAX_FILE_LEN : fileName.size());
+            apr_uid_t uid; 
+            apr_gid_t groupid;
+            apr_status_t stat = apr_uid_current(&uid, &groupid, 
pool.getAPRPool());
+            if (stat == APR_SUCCESS){
+                snprintf(szUid, MAX_FILE_LEN, "%u", uid);
             }
-          } else {
-            OutputStreamPtr os(new FileOutputStream(
-                  rollover1->getActiveFileName(), rollover1->getAppend()));
-            WriterPtr newWriter(createWriter(os));
-            closeWriter();
-            setFile(rollover1->getActiveFileName());
-            setWriter(newWriter);
-
-            bool success = true;
-
-            if (rollover1->getSynchronous() != NULL) {
-              success = false;
-
-              try {
-                success = rollover1->getSynchronous()->execute(p);
-              } catch (std::exception& ex) {
-                LogLog::warn(LOG4CXX_STR("Exception during rollover"));
-              }
+
+            const std::string lockname = std::string(::dirname(szDirName)) + 
"/." + ::basename(szBaseName) + szUid + ".lock";
+            apr_file_t* lock_file;
+            stat = apr_file_open(&lock_file, lockname.c_str(), APR_CREATE | 
APR_READ | APR_WRITE, APR_OS_DEFAULT, p.getAPRPool());
+            if (stat != APR_SUCCESS) {
+                std::string err = "lockfile return error: open lockfile 
failed. ";
+                err += (strerror(errno));
+                LogLog::warn(LOG4CXX_STR(err.c_str()));
+                bAlreadyRolled = false;
+                lock_file = NULL;
+            }else{
+                stat = apr_file_lock(lock_file, APR_FLOCK_EXCLUSIVE);
+                if (stat != APR_SUCCESS){
+                    std::string err = "apr_file_lock: lock failed. ";
+                    err += (strerror(errno));
+                    LogLog::warn(LOG4CXX_STR(err.c_str()));
+                    bAlreadyRolled = false;
+                }
+                else {
+                    if (_event)
+                        triggeringPolicy->isTriggeringEvent(this, *_event, 
getFile(), getFileLength());
+                }
             }
 
-            if (success) {
-              if (rollover1->getAppend()) {
-                fileLength = 
File().setPath(rollover1->getActiveFileName()).length(p);
-              } else {
-                fileLength = 0;
-              }
-
-              //
-              //   async action not yet implemented
-              //
-              ActionPtr asyncAction(rollover1->getAsynchronous());
-              if (asyncAction != NULL) {
-                asyncAction->execute(p);
-              }
+            if (bAlreadyRolled){
+                apr_finfo_t finfo1, finfo2;
+                apr_status_t st1, st2;
+                apr_file_t* _fd = 
getWriter()->getOutPutStreamPtr()->getFileOutPutStreamPtr().getFilePtr(); 
+                st1 = apr_file_info_get(&finfo1, APR_FINFO_IDENT, _fd);
+                if (st1 != APR_SUCCESS){
+                    LogLog::warn(LOG4CXX_STR("apr_file_info_get failed"));
+                }
+
+                st2 = apr_stat(&finfo2, std::string(getFile()).c_str(), 
APR_FINFO_IDENT, p.getAPRPool());
+                if (st2 != APR_SUCCESS){
+                    LogLog::warn(LOG4CXX_STR("apr_stat failed."));
+                }
+
+                bAlreadyRolled = ((st1 == APR_SUCCESS) && (st2 == APR_SUCCESS) 
+                    && ((finfo1.device != finfo2.device) || (finfo1.inode != 
finfo2.inode)));
             }
+                    
+            if (!bAlreadyRolled){
+#endif
+                try {
+                    RolloverDescriptionPtr 
rollover1(rollingPolicy->rollover(getFile(), p));
+                    if (rollover1 != NULL) {
+                        if (rollover1->getActiveFileName() == getFile()) {
+                            closeWriter();
+
+                            bool success = true;
+                            if (rollover1->getSynchronous() != NULL) {
+                                success = false;
+
+                                try {
+                                    success = 
rollover1->getSynchronous()->execute(p);
+                                } catch (std::exception& ex) {
+                                    LogLog::warn(LOG4CXX_STR("Exception on 
rollover"));
+                                }
+                            }
+
+                            if (success) {
+                                if (rollover1->getAppend()) {
+                                    fileLength = 
File().setPath(rollover1->getActiveFileName()).length(p);
+                                } else {
+                                    fileLength = 0;
+                                }
+
+                                //
+                                //  async action not yet implemented
+                                //
+                                ActionPtr 
asyncAction(rollover1->getAsynchronous());
+                                if (asyncAction != NULL) {
+                                    asyncAction->execute(p);
+                                }
+
+                                setFile(
+                                    rollover1->getActiveFileName(), 
rollover1->getAppend(),
+                                    bufferedIO, bufferSize, p);
+                            } else {
+                                setFile(
+                                    rollover1->getActiveFileName(), true, 
bufferedIO, bufferSize, p);
+                            }
+                        } else {
+                            OutputStreamPtr os(new FileOutputStream(
+                                    rollover1->getActiveFileName(), 
rollover1->getAppend()));
+                            WriterPtr newWriter(createWriter(os));
+                            closeWriter();
+                            setFile(rollover1->getActiveFileName());
+                            setWriter(newWriter);
+
+                            bool success = true;
+
+                            if (rollover1->getSynchronous() != NULL) {
+                                success = false;
+
+                                try {
+                                    success = 
rollover1->getSynchronous()->execute(p);
+                                } catch (std::exception& ex) {
+                                    LogLog::warn(LOG4CXX_STR("Exception during 
rollover"));
+                                }
+                            }
+
+                            if (success) {
+                                if (rollover1->getAppend()) {
+                                    fileLength = 
File().setPath(rollover1->getActiveFileName()).length(p);
+                                } else {
+                                    fileLength = 0;
+                                }
+
+                                //
+                                //   async action not yet implemented
+                                //
+                                ActionPtr 
asyncAction(rollover1->getAsynchronous());
+                                if (asyncAction != NULL) {
+                                    asyncAction->execute(p);
+                                }
+                            }
 
-            writeHeader(p);
-          }
+                            writeHeader(p);
+                        }
 
-          return true;
+#ifdef LOG4CXX_MULTI_PROCESS
+                        releaseFileLock(lock_file);
+#endif
+                        return true;
+                    }
+                } catch (std::exception& ex) {
+                    LogLog::warn(LOG4CXX_STR("Exception during rollover"));
+                }
+#ifdef LOG4CXX_MULTI_PROCESS
+            }else{
+                reopenLatestFile(p);
+            }
+            releaseFileLock(lock_file);
+#endif
         }
-      } catch (std::exception& ex) {
-        LogLog::warn(LOG4CXX_STR("Exception during rollover"));
-      }
     }
+    return false;
+}
 
-  }
-
-  return false;
+#ifdef LOG4CXX_MULTI_PROCESS
+/**
+ * re-open current file when its own handler has been renamed
+ */
+void RollingFileAppenderSkeleton::reopenLatestFile(Pool& p){
+    closeWriter(); 
+    OutputStreamPtr os(new FileOutputStream(getFile(), true));
+    WriterPtr newWriter(createWriter(os));
+    setFile(getFile());
+    setWriter(newWriter);
+    fileLength = File().setPath(getFile()).length(p);
+    writeHeader(p);
 }
 
+#endif
+
 /**
  * {@inheritDoc}
 */
@@ -248,11 +363,38 @@ void RollingFileAppenderSkeleton::subApp
     //    is not provided.  However appender should still be in good
     //     condition and the append should still happen.
     try {
-      rollover(p);
+        _event = &(const_cast<LoggingEventPtr &>(event));
+        rollover(p);
     } catch (std::exception& ex) {
         LogLog::warn(LOG4CXX_STR("Exception during rollover attempt."));
     }
   }
+
+#ifdef LOG4CXX_MULTI_PROCESS
+  //do re-check before every write 
+  //
+  apr_finfo_t finfo1, finfo2;
+  apr_status_t st1, st2;
+  apr_file_t* _fd = 
getWriter()->getOutPutStreamPtr()->getFileOutPutStreamPtr().getFilePtr(); 
+  st1 = apr_file_info_get(&finfo1, APR_FINFO_IDENT, _fd);
+  if (st1 != APR_SUCCESS){
+      LogLog::warn(LOG4CXX_STR("apr_file_info_get failed"));
+  }
+
+  st2 = apr_stat(&finfo2, std::string(getFile()).c_str(), APR_FINFO_IDENT, 
p.getAPRPool());
+  if (st2 != APR_SUCCESS){
+      std::string err = "apr_stat failed. file:" + std::string(getFile());
+      LogLog::warn(LOG4CXX_STR(err.c_str()));
+  }
+
+  bool bAlreadyRolled = ((st1 == APR_SUCCESS) && (st2 == APR_SUCCESS) 
+      && ((finfo1.device != finfo2.device) || (finfo1.inode != finfo2.inode)));
+
+  if (bAlreadyRolled){
+      reopenLatestFile(p);
+  }
+#endif
+
   FileAppender::subAppend(event, p);
 }
 
@@ -345,10 +487,17 @@ class CountingOutputStream : public Outp
   void write(ByteBuffer& buf, Pool& p) {
     os->write(buf, p);
     if (rfa != 0) {
+#ifndef LOG4CXX_MULTI_PROCESS
         rfa->incrementFileLength(buf.limit());
+#else
+        rfa->setFileLength(File().setPath(rfa->getFile()).length(p));
+#endif
     }
   }
 
+#ifdef LOG4CXX_MULTI_PROCESS
+  OutputStream& getFileOutPutStreamPtr() { return *os;}
+#endif
 };
   }
 }
@@ -375,6 +524,12 @@ size_t RollingFileAppenderSkeleton::getF
   return fileLength;
 }
 
+#ifdef LOG4CXX_MULTI_PROCESS 
+void RollingFileAppenderSkeleton::setFileLength(size_t length){
+    fileLength = length;
+}
+#endif
+
 /**
  * Increments estimated byte length of current active log file.
  * @param increment additional bytes written to log file.

Modified: incubator/log4cxx/trunk/src/main/cpp/timebasedrollingpolicy.cpp
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/timebasedrollingpolicy.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- incubator/log4cxx/trunk/src/main/cpp/timebasedrollingpolicy.cpp (original)
+++ incubator/log4cxx/trunk/src/main/cpp/timebasedrollingpolicy.cpp Sun Feb  9 
18:26:33 2014
@@ -18,6 +18,10 @@
 #pragma warning ( disable: 4231 4251 4275 4786 )
 #endif
 
+#ifdef LOG4CXX_MULTI_PROCESS 
+#include <libgen.h>
+#endif 
+
 #include <log4cxx/logstring.h>
 #include <log4cxx/rolling/timebasedrollingpolicy.h>
 #include <log4cxx/pattern/filedatepatternconverter.h>
@@ -27,6 +31,8 @@
 #include <log4cxx/helpers/exception.h>
 #include <log4cxx/rolling/gzcompressaction.h>
 #include <log4cxx/rolling/zipcompressaction.h>
+#include <log4cxx/rolling/rollingfileappenderskeleton.h>
+#include<iostream>
 
 #ifndef INT64_C
 #define INT64_C(x) x ## LL
@@ -34,7 +40,6 @@
 
 #include <apr_time.h>
 
-
 using namespace log4cxx;
 using namespace log4cxx::rolling;
 using namespace log4cxx::helpers;
@@ -42,8 +47,110 @@ using namespace log4cxx::pattern;
 
 IMPLEMENT_LOG4CXX_OBJECT(TimeBasedRollingPolicy)
 
-TimeBasedRollingPolicy::TimeBasedRollingPolicy() {
+#ifdef LOG4CXX_MULTI_PROCESS 
+#define MMAP_FILE_SUFFIX ".map"
+#define LOCK_FILE_SUFFIX ".maplck"
+#define MAX_FILE_LEN 2048 
+
+bool TimeBasedRollingPolicy::isMapFileEmpty(log4cxx::helpers::Pool& pool){
+    apr_finfo_t finfo;
+    apr_status_t st = apr_stat(&finfo, _mapFileName.c_str(), APR_FINFO_SIZE, 
pool.getAPRPool());
+    if (st != APR_SUCCESS){
+        LogLog::warn(LOG4CXX_STR("apr_stat failed."));
+    }
+    if (st == APR_SUCCESS && !finfo.size)
+        return true;
+    return false;
+}
+
+void TimeBasedRollingPolicy::initMMapFile(const LogString& lastFileName, 
log4cxx::helpers::Pool& pool){
+    int iRet = 0;
+    if (!_mmap){
+        iRet = createMMapFile(std::string(_fileNamePattern), pool);
+    }
+    if (!iRet && isMapFileEmpty(pool)) {
+        lockMMapFile(APR_FLOCK_EXCLUSIVE);
+        memset(_mmap->mm, 0, MAX_FILE_LEN);
+        memcpy(_mmap->mm, std::string(lastFileName).c_str(), 
std::string(lastFileName).size());
+        unLockMMapFile();
+    }
+}
+
+const std::string TimeBasedRollingPolicy::createFile(const std::string& 
fileName, const std::string& suffix, log4cxx::helpers::Pool& pool) {
+   char szUid[MAX_FILE_LEN] = {'\0'};
+   char szBaseName[MAX_FILE_LEN] = {'\0'};
+   char szDirName[MAX_FILE_LEN] = {'\0'};
+   memcpy(szDirName, fileName.c_str(), fileName.size() > MAX_FILE_LEN ? 
MAX_FILE_LEN : fileName.size());
+   memcpy(szBaseName, fileName.c_str(), fileName.size() > MAX_FILE_LEN ? 
MAX_FILE_LEN : fileName.size());
+
+   apr_uid_t uid; 
+   apr_gid_t groupid;
+   apr_status_t stat = apr_uid_current(&uid, &groupid, pool.getAPRPool());
+   if (stat == APR_SUCCESS){
+       snprintf(szUid, MAX_FILE_LEN, "%u", uid);
+   }
+   return std::string(::dirname(szDirName)) + "/." + ::basename(szBaseName) + 
szUid + suffix;
+}
+
+int TimeBasedRollingPolicy::createMMapFile(const std::string& fileName, 
log4cxx::helpers::Pool& pool){
+   _mapFileName = createFile(fileName, MMAP_FILE_SUFFIX, pool);
+
+   apr_status_t stat = apr_file_open(&_file_map, _mapFileName.c_str(), 
APR_CREATE | APR_READ | APR_WRITE, APR_OS_DEFAULT, _mmapPool->getAPRPool());
+   if (stat != APR_SUCCESS){
+        std::string err(std::string("open mmap file failed. ") + 
std::string(strerror(errno)) + ". Check the privilege or try to remove " + 
_mapFileName + " if exist.");
+        LogLog::warn(LOG4CXX_STR(err.c_str()));
+        return -1;
+   }
+
+   if (isMapFileEmpty(pool)){
+       stat = apr_file_trunc(_file_map, MAX_FILE_LEN + 1);
+       if (stat != APR_SUCCESS){
+           LogLog::warn(LOG4CXX_STR("apr_file_trunc failed."));
+           apr_file_close(_file_map);
+           return -1;
+       }
+   }
+
+   stat = apr_mmap_create(&_mmap, _file_map, 0, MAX_FILE_LEN, APR_MMAP_WRITE | 
APR_MMAP_READ, _mmapPool->getAPRPool());
+   if (stat != APR_SUCCESS){
+       LogLog::warn(LOG4CXX_STR("mmap failed."));
+       apr_file_close(_file_map);
+       return -1;
+   }
+
+   return 0;
+}
+
+int TimeBasedRollingPolicy::lockMMapFile(int type)
+{
+    apr_status_t stat = apr_file_lock(_lock_file, type);
+    if (stat != APR_SUCCESS) {
+        LogLog::warn(LOG4CXX_STR("apr_file_lock for mmap failed."));
+    }
+}
+int TimeBasedRollingPolicy::unLockMMapFile()
+{
+    apr_status_t stat = apr_file_unlock(_lock_file);
+    if (stat != APR_SUCCESS) {
+        LogLog::warn(LOG4CXX_STR("apr_file_unlock for mmap failed."));
+    }
+}
+
+#endif
+
+TimeBasedRollingPolicy::TimeBasedRollingPolicy() 
+#ifdef LOG4CXX_MULTI_PROCESS 
+    :_mmap(NULL), _file_map(NULL), bAlreadyInitialized(false), _mmapPool(new 
Pool()), _lock_file(NULL), bRefreshCurFile(false)
+#endif
+{
+}
+
+#ifdef LOG4CXX_MULTI_PROCESS 
+TimeBasedRollingPolicy::~TimeBasedRollingPolicy() {
+    //no-need to delete mmap
+    delete _mmapPool;
 }
+#endif
 
 void TimeBasedRollingPolicy::addRef() const {
     TriggeringPolicy::addRef();
@@ -75,6 +182,24 @@ void TimeBasedRollingPolicy::activateOpt
     formatFileName(obj, buf, pool);
     lastFileName = buf;
 
+#ifdef LOG4CXX_MULTI_PROCESS
+    if (getPatternConverterList().size()){
+        (*(getPatternConverterList().begin()))->format(obj, _fileNamePattern, 
pool);
+    }else{
+        _fileNamePattern = lastFileName;
+    }
+
+    if (!_lock_file) {
+        const std::string lockname = createFile(std::string(_fileNamePattern), 
LOCK_FILE_SUFFIX, *_mmapPool);
+        apr_status_t stat = apr_file_open(&_lock_file, lockname.c_str(), 
APR_CREATE | APR_READ | APR_WRITE, APR_OS_DEFAULT, (*_mmapPool).getAPRPool());
+        if (stat != APR_SUCCESS) {
+            LogLog::warn(LOG4CXX_STR("open lock file failed."));
+        }
+    }
+    
+    initMMapFile(lastFileName, *_mmapPool);
+#endif
+
     suffixLength = 0;
 
     if (lastFileName.length() >= 3) {
@@ -120,6 +245,7 @@ RolloverDescriptionPtr TimeBasedRollingP
     return new RolloverDescription(
       currentActiveFile, append, noAction, noAction);
   } else {
+      bRefreshCurFile = true;
     return new RolloverDescription(
       lastFileName.substr(0, lastFileName.length() - suffixLength), append,
       noAction, noAction);
@@ -140,6 +266,19 @@ RolloverDescriptionPtr TimeBasedRollingP
 
   LogString newFileName(buf);
 
+#ifdef LOG4CXX_MULTI_PROCESS
+  bAlreadyInitialized = true;
+  if (_mmap && !isMapFileEmpty(*_mmapPool)){
+      lockMMapFile(APR_FLOCK_SHARED);
+      LogString mapLastFile((char *)_mmap->mm);
+      lastFileName = mapLastFile;
+      unLockMMapFile();
+  }else{
+      _mmap = NULL;
+      initMMapFile(lastFileName, *_mmapPool);
+  }
+#endif
+
   //
   //  if file names haven't changed, no rollover
   //
@@ -178,18 +317,48 @@ RolloverDescriptionPtr TimeBasedRollingP
         File().setPath(lastBaseName), File().setPath(lastFileName), true);
   }
 
+#ifdef LOG4CXX_MULTI_PROCESS
+  if (_mmap && !isMapFileEmpty(*_mmapPool)){
+      lockMMapFile(APR_FLOCK_EXCLUSIVE);
+      memset(_mmap->mm, 0, MAX_FILE_LEN);
+      memcpy(_mmap->mm, std::string(newFileName).c_str(), 
std::string(newFileName).size());
+      unLockMMapFile();
+  }else{
+      _mmap = NULL;
+      initMMapFile(newFileName, *_mmapPool);
+  }
+#else
   lastFileName = newFileName;
+#endif
 
+#ifdef LOG4CXX_MULTI_PROCESS
+  return new RolloverDescription(
+    nextActiveFile, true, renameAction, compressAction);
+#else
   return new RolloverDescription(
     nextActiveFile, false, renameAction, compressAction);
+#endif
 }
 
 
 
 bool TimeBasedRollingPolicy::isTriggeringEvent(
-  Appender* /* appender */,
+  Appender* appender,
   const log4cxx::spi::LoggingEventPtr& /* event */,
-  const LogString& /* filename */,
+  const LogString&  filename ,
   size_t /* fileLength */)  {
+#ifdef LOG4CXX_MULTI_PROCESS
+    if (bRefreshCurFile && _mmap && !isMapFileEmpty(*_mmapPool)) {
+        lockMMapFile(APR_FLOCK_SHARED);
+        LogString mapCurrent((char *)_mmap->mm);
+        unLockMMapFile();
+        LogString mapCurrentBase(mapCurrent.substr(0, mapCurrent.length() - 
suffixLength));
+        if (!mapCurrentBase.empty() && mapCurrentBase != filename) {
+            dynamic_cast<FileAppender *>(appender)->setFile(mapCurrentBase);
+        }
+    }
+    return ((apr_time_now()) > nextCheck) || (!bAlreadyInitialized);
+#else
     return apr_time_now() > nextCheck;
+#endif
 }

Modified: incubator/log4cxx/trunk/src/main/cpp/writer.cpp
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/writer.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- incubator/log4cxx/trunk/src/main/cpp/writer.cpp (original)
+++ incubator/log4cxx/trunk/src/main/cpp/writer.cpp Sun Feb  9 18:26:33 2014
@@ -17,6 +17,7 @@
 
 #include <log4cxx/logstring.h>
 #include <log4cxx/helpers/writer.h>
+#include <stdexcept>
 
 using namespace log4cxx::helpers;
 
@@ -27,3 +28,9 @@ Writer::Writer() {
 
 Writer::~Writer() {
 }
+
+#ifdef LOG4CXX_MULTI_PROCESS                  
+OutputStreamPtr Writer::getOutPutStreamPtr(){
+    throw std::logic_error("getOutPutStreamPtr must be implemented in the 
derived class that you are using");
+}
+#endif

Modified: 
incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/fileoutputstream.h
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/fileoutputstream.h?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/fileoutputstream.h 
(original)
+++ incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/fileoutputstream.h 
Sun Feb  9 18:26:33 2014
@@ -52,6 +52,9 @@ namespace log4cxx
                   virtual void flush(Pool& p);
                   virtual void write(ByteBuffer& buf, Pool& p);
 
+#ifdef LOG4CXX_MULTI_PROCESS
+                  apr_file_t* getFilePtr() { return fileptr; }
+#endif
           private:
                   FileOutputStream(const FileOutputStream&);
                   FileOutputStream& operator=(const FileOutputStream&);

Modified: 
incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstream.h
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstream.h?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstream.h 
(original)
+++ incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstream.h Sun 
Feb  9 18:26:33 2014
@@ -19,6 +19,9 @@
 #define _LOG4CXX_HELPERS_OUTPUTSTREAM_H
 
 #include <log4cxx/helpers/objectimpl.h>
+#ifdef LOG4CXX_MULTI_PROCESS
+#include <apr_file_io.h>
+#endif
 
 namespace log4cxx
 {
@@ -45,6 +48,10 @@ namespace log4cxx
                   virtual void close(Pool& p) = 0;
                   virtual void flush(Pool& p) = 0;
                   virtual void write(ByteBuffer& buf, Pool& p) = 0;
+#ifdef LOG4CXX_MULTI_PROCESS
+                  virtual apr_file_t* getFilePtr();
+                  virtual OutputStream& getFileOutPutStreamPtr();
+#endif
 
           private:
                   OutputStream(const OutputStream&);

Modified: 
incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstreamwriter.h
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstreamwriter.h?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- 
incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstreamwriter.h 
(original)
+++ 
incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstreamwriter.h 
Sun Feb  9 18:26:33 2014
@@ -52,6 +52,10 @@ namespace log4cxx
                   virtual void write(const LogString& str, Pool& p);
                   LogString getEncoding() const;
 
+#ifdef LOG4CXX_MULTI_PROCESS
+                  OutputStreamPtr getOutPutStreamPtr() { return out; }
+#endif
+
           private:
                   OutputStreamWriter(const OutputStreamWriter&);
                   OutputStreamWriter& operator=(const OutputStreamWriter&);

Modified: incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/writer.h
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/writer.h?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/writer.h (original)
+++ incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/writer.h Sun Feb  
9 18:26:33 2014
@@ -19,6 +19,7 @@
 #define _LOG4CXX_HELPERS_WRITER_H
 
 #include <log4cxx/helpers/objectimpl.h>
+#include <log4cxx/helpers/outputstream.h>
 
 namespace log4cxx
 {
@@ -44,6 +45,9 @@ namespace log4cxx
                   virtual void close(Pool& p) = 0;
                   virtual void flush(Pool& p) = 0;
                   virtual void write(const LogString& str, Pool& p) = 0;
+#ifdef LOG4CXX_MULTI_PROCESS
+                  virtual OutputStreamPtr getOutPutStreamPtr();
+#endif
 
           private:
                   Writer(const Writer&);

Modified: 
incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- 
incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h
 (original)
+++ 
incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h
 Sun Feb  9 18:26:33 2014
@@ -57,6 +57,10 @@ namespace log4cxx {
            */
           size_t fileLength;
 
+          /**
+           *  save the loggingevent
+           */
+          spi::LoggingEventPtr* _event;
         public:
           /**
            * The default constructor simply calls its {@link
@@ -133,6 +137,25 @@ namespace log4cxx {
            * @return byte length of current active log file.
            */
           size_t getFileLength() const;
+          
+#ifdef LOG4CXX_MULTI_PROCESS
+          /**
+           * Set byte length of current active log file.
+           * @return void
+           */
+          void setFileLength(size_t length);
+
+          /**
+           *  Release the file lock
+           * @return void
+           */
+          void releaseFileLock(apr_file_t* lock_file);
+          /**
+           * re-open the latest file when its own handler has been renamed
+           * @return void
+           */
+          void reopenLatestFile(log4cxx::helpers::Pool& p);
+#endif
 
           /**
            * Increments estimated byte length of current active log file.

Modified: 
incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingpolicybase.h
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingpolicybase.h?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- 
incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingpolicybase.h 
(original)
+++ 
incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingpolicybase.h 
Sun Feb  9 18:26:33 2014
@@ -96,6 +96,9 @@ namespace log4cxx {
            LogString getFileNamePattern() const;
 
 
+#ifdef LOG4CXX_MULTI_PROCESS                
+           PatternConverterList getPatternConverterList() { return 
patternConverters; }
+#endif
            protected:
            /**
             *   Parse file name pattern.

Modified: 
incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/timebasedrollingpolicy.h
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/timebasedrollingpolicy.h?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- 
incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/timebasedrollingpolicy.h
 (original)
+++ 
incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/timebasedrollingpolicy.h
 Sun Feb  9 18:26:33 2014
@@ -22,6 +22,9 @@
 #include <log4cxx/portability.h>
 #include <log4cxx/rolling/rollingpolicybase.h>
 #include <log4cxx/rolling/triggeringpolicy.h>
+#include <log4cxx/writerappender.h>
+#include <log4cxx/helpers/outputstream.h>
+#include <apr_mmap.h>
 
 namespace log4cxx {
 
@@ -157,6 +160,50 @@ namespace log4cxx {
         LogString lastFileName;
 
         /**
+         * mmap pointer
+         */
+        apr_mmap_t* _mmap;
+
+        /*
+         * pool for mmap handler
+         * */
+        log4cxx::helpers::Pool* _mmapPool;
+        
+        /**
+         * mmap file descriptor
+         */
+        apr_file_t* _file_map;
+
+        /**
+         * mmap file name 
+         */
+        std::string _mapFileName;
+
+        /*
+         * lock file handle
+         * */
+        apr_file_t* _lock_file;
+        /**
+         * Check nextCheck if it has already been set
+         * Timebased rolling policy has an issue when working at low rps.
+         * Under low rps, multiple processes will not be scheduled in time for 
the second chance(do rolling),
+         * so the rolling mechanism will not be triggered even if the time 
period is out of date.
+         * This results in log entries will be accumulated for serveral 
minutes to be rolling.
+         * Adding this flag to provide rolling opportunity for a process even 
if it is writing the first log entry
+         */
+        bool bAlreadyInitialized;
+
+        /*
+         * If the current file name contains date information, retrieve the 
current writting file from mmap
+         * */
+        bool bRefreshCurFile;
+
+        /*
+         * mmap file name
+         * */
+        LogString _fileNamePattern;
+
+        /**
          * Length of any file type suffix (.gz, .zip).
          */
         int suffixLength;
@@ -166,6 +213,41 @@ namespace log4cxx {
             void addRef() const;
             void releaseRef() const;
             void activateOptions(log4cxx::helpers::Pool& );
+
+#ifdef LOG4CXX_MULTI_PROCESS
+            virtual ~TimeBasedRollingPolicy();
+
+            /**
+             * Generate mmap file
+             */
+            int createMMapFile(const std::string& lastfilename, 
log4cxx::helpers::Pool& pool);
+
+            /**
+             *  Detect if the mmap file is empty
+             */
+            bool isMapFileEmpty(log4cxx::helpers::Pool& pool);
+
+            /**
+             *   init MMapFile
+             */
+            void initMMapFile(const LogString& lastFileName, 
log4cxx::helpers::Pool& pool);
+
+            /**
+             *   lock MMapFile
+             */
+            int lockMMapFile(int type);
+
+            /**
+             *   unlock MMapFile
+             */
+            int unLockMMapFile();
+
+            /**
+             *   create MMapFile/lockFile
+             */
+            const std::string createFile(const std::string& filename, const 
std::string& suffix, log4cxx::helpers::Pool& pool);
+#endif
+
             /**
            * Initialize the policy and return any initial actions for rolling 
file appender.
            *

Modified: incubator/log4cxx/trunk/src/main/include/log4cxx/writerappender.h
URL: 
http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/writerappender.h?rev=1566343&r1=1566342&r2=1566343&view=diff
==============================================================================
--- incubator/log4cxx/trunk/src/main/include/log4cxx/writerappender.h (original)
+++ incubator/log4cxx/trunk/src/main/include/log4cxx/writerappender.h Sun Feb  
9 18:26:33 2014
@@ -179,6 +179,9 @@ namespace log4cxx
                   <p>
                   @param writer An already opened Writer.  */
                 void setWriter(const log4cxx::helpers::WriterPtr& writer);
+#ifdef LOG4CXX_MULTI_PROCESS                
+                const log4cxx::helpers::WriterPtr getWriter() { return writer; 
};
+#endif
 
                 virtual bool requiresLayout() const;
 


Reply via email to