BIND 10 #1704: log output mixed

BIND 10 Development do-not-reply at isc.org
Wed May 23 21:42:33 UTC 2012


#1704: log output mixed
-------------------------------------+-------------------------------------
                   Reporter:  jreed  |                 Owner:  jinmei
                       Type:         |                Status:  reviewing
  defect                             |             Milestone:
                   Priority:         |  Sprint-20120529
  medium                             |            Resolution:
                  Component:         |             Sensitive:  0
  logging                            |           Sub-Project:  Core
                   Keywords:         |  Estimated Difficulty:  15
            Defect Severity:  N/A    |           Total Hours:  0
Feature Depending on Ticket:         |
        Add Hours to Ticket:  0      |
                  Internal?:  0      |
-------------------------------------+-------------------------------------

Comment (by jinmei):

 '''General'''

 - The new version still needed editorial nits.  I made them directly
   to the branch.  Please check.  Maybe we need a common checker script
   because some conventions seem to be so difficult to follow for new
   developers (but that's not a topic of this branch).
 - (not specific to this version; sorry I forgot to mention this
   before) How does it work for multi-thread components?  Right now, some
   python daemons use multiple threads.  Although we'll probably get rid
   of them according to the previous f2f discussions, but I guess
   b10-resolver will eventually be multi-threaded.
 - About the design: it now looks much better, but I don't see why we
   need the separate class hierarchy for `InterprocessSync`.  If I were
   to implement it, I'd simply include all file-related logic in
   `InterprocessSyncFile` (which I'd call `InterprocessSyncFileLock`)
   and make `InterprocessSyncLocker` a value  (i.e., not a base) class:
 {{{#!cpp
 class InterprocessSyncLocker {
 public:
     InterprocessSyncLocker(InterprocessLock& lock) :
         locked_(false), lock_(lock) {}
     ~InterprocessSyncLocker() {
         unlock();
     }
     void lock() {
         if (locked_) {
             lock_.lock();
             locked_ = true;
         }
     }
     void unlock() {
         if (locked_) {
             lock_.unlock();
             locked_ = false;
         }
     }
 private:
     bool locked_;
     InterprocessLock& lock_;
 };
 }}}
   This way we can avoid newing the locker, avoid using friend, and
   avoid using dynamic_cast.  With this approach
   `LoggerImpl::outputRaw()` would look like this:
 {{{#!cpp
 void
 LoggerImpl::outputRaw(const Severity& severity, const string& message) {
     InterprocessSyncLocker locker(*sync_);
     locker.lock();

     LOG4CPLUS_DEBUG(logger_, message);  //, and so on

     // Lock will be automatically released.
 }
 }}}

 '''logger implementation'''

 Maybe you're planning it, but we'll still need to test the logger
 behavior.  As I suggested, I'd use some mock lock class.  Also, in
 that case, we'll probably not have to set the magic B10_FROM variable
 for tests.

 '''interprocess_sync_file'''

 - it's better to make component_name `const string&` (cppcheck will
   even fail due to that):
 {{{#!cpp
     /// \brief Constructor
     InterprocessSyncFile(const std::string component_name);
 }}}

 - lock/unlock/tryLock share almost the same code pattern.  I'd somehow
   combine them (note, however, that we might not need tryLock in the
   first place; see below)

 - top source dir may not be writable, so we should use somewhere
   always writable e.g., top_builddir:
 {{{#!cpp
     const char* const env = getenv("B10_FROM_SOURCE");
     if (env != NULL) {
         lockfile_path = env;
     }
 }}}

 '''interprocess_sync_file_unittest'''

 - As far as I can see `InterprocessSyncFileTest` doesn't have to be a
   fixture (i.e. no class for it, replace TEST_F with TEST)
 - Overall the code is not exception safe wrt dynamic allocation, e.g.:
 {{{#!cpp
   InterprocessSync* sync = new InterprocessSyncFile("test");
   InterprocessSyncLocker* locker = sync->getLocker();
 }}}
   Although in tests it may not a big deal in practice, I'd generally
   like to keep any code in our tree as clean as possible.  In these
   cases we should be easily able to make it safe with
   boost::scoped_ptr.
 - I'd rather specify the full path than relying on the B10_FROM_ trick
   with setting in main() globally:
 {{{#!cpp
   InterprocessSync* sync = new InterprocessSyncFile("test");
 }}}
   Setting this environment variable could affect other tests, and the
   full path is in fact closer to what would be used in the actual
   deployment.  Note that if we do this we can/should remove setenv
   from main().
 - TestLock: pipe(2) can fail.  I'd explicitly check the return value
   either by assert or ASSERT_NE, or by throwing an exception on
   failure.
 - same for fork(), read(), write() (and technically, close(), although
   we can probably say it should be so unlikely that it's not worth
   checking in this context)
 - Testing tryLock() is suboptimal because in the real logger code we
   don't use it.  Since we are now free from the logging context, I'd
   suggest using lock() for actually writing something to the file.
   Both the parent and child would write something to the file, in that
   order ensured by the lock, and we can check what is written.  (Of
   course, though, this test could incorrectly pass depending on the
   timing).  Note also that if we take this approach, we can probably
   just remove tryLock(), at least until we really need it in an
   application.
 - read() at the parent could block if there's an unexpected bug in the
   child part, and in the worst case the whole test could hang.  I'd
   try avoiding that scenario as much as possible.  For example, we can
   introduce a timeout for read(); we can also make sure the child
   really dies in some way.
 - this can be simplified:
 {{{#!cpp
       if (locked == 1) {
         was_locked = true;
       } else {
         was_locked = false;
       }
 ...
   EXPECT_TRUE(was_locked);
 }}}
   as:
 {{{#!cpp
       EXPECT_EQ(1, locked);
 }}}
   and we can remove was_locked completely.  Same for
   TestMultipleFilesForked with was_not_locked.

-- 
Ticket URL: <http://bind10.isc.org/ticket/1704#comment:50>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list