[svn] commit: r391 - in /branches/jinmei-dnsmessageapi/src/lib/dns/cpp: messagerenderer.cc messagerenderer.h

BIND 10 source code commits bind10-changes at lists.isc.org
Sat Dec 19 03:16:26 UTC 2009


Author: jinmei
Date: Sat Dec 19 03:16:26 2009
New Revision: 391

Log:
documented the message renderer class

Modified:
    branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.cc
    branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.h

Modified: branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.cc
==============================================================================
--- branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.cc (original)
+++ branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.cc Sat Dec 19 03:16:26 2009
@@ -27,23 +27,48 @@
 namespace isc {
 namespace dns {
 
+namespace {     // hide internal-only names from the public namespaces
+///
+/// \brief The \c NameCompressNode class represents a pointer to a name
+/// rendered in the internal buffer for the \c MessageRendererImpl object.
+///
+/// A \c MessageRendererImpl object maintains a set of the \c NameCompressNode
+/// objects, and searches the set for the position of the longest match
+/// (ancestor) name against each new name to be rendered into the buffer.
 struct NameCompressNode {
     NameCompressNode(const OutputBuffer& buffer, size_t pos, size_t len) :
         buffer_(buffer), pos_(pos), len_(len) {}
+    /// The buffer in which the corresponding name is rendered.
     const OutputBuffer& buffer_;
+    /// The position (offset from the beginning) in the buffer where the
+    /// name starts.
     uint16_t pos_;
+    /// The length of the corresponding name.
     uint16_t len_;
 };
 
 ///
-/// Helper class to give ordering for MessageRendererImpl::nodeset_.
-///
+/// \brief The \c NameCompare class is a functor that gives ordering among
+/// \c NameCompressNode objects stored in \c MessageRendererImpl::nodeset_.
+///
+/// Its only public method as a functor, \c operator(), gives the ordering
+/// between two \c NameCompressNode objects in terms of equivalence, that is,
+/// returns whether one is "less than" the other.
+/// For our purpose we only need to distinguish two different names, so the
+/// ordering is different from the canonical DNS name order used in DNSSEC;
+/// basically, it gives the case-insensitive ordering of the two names as their
+/// textual representation.
 struct NameCompare : public std::binary_function<NameCompressNode,
                                                  NameCompressNode,
                                                  bool> {
     ///
     /// Returns true if n1 < n2 as a result of case-insensitive comparison;
     /// otherwise return false.
+    ///
+    /// The name corresponding to \c n1 or \c n2 may be compressed, in which
+    /// case we must follow the compression pointer in the associated buffer.
+    /// The helper private method \c nextPosition() gives the position in the
+    /// buffer for the next character, taking into account compression.
     ///
     bool operator()(const NameCompressNode& n1,
                     const NameCompressNode& n2) const
@@ -71,13 +96,16 @@
         return (false);
     }
 
+private:
     uint16_t nextPosition(const OutputBuffer& buffer,
                           uint16_t pos, uint16_t& llen) const
     {
         if (llen == 0) {
             int i = 0;
-            while ((buffer[pos] & 0xc0) == 0xc0) {
-                pos = (buffer[pos] & 0x3f) * 256 + buffer[pos + 1];
+            while ((buffer[pos] & Name::COMPRESS_POINTER_MARK8) ==
+                   Name::COMPRESS_POINTER_MARK8) {
+                pos = (buffer[pos] & ~Name::COMPRESS_POINTER_MARK8) *
+                    256 + buffer[pos + 1];
 
                 // This loop should stop as long as the buffer has been
                 // constructed validly and the search/insert argument is based
@@ -92,19 +120,36 @@
         return (pos);
     }
 };
-
+}
+
+///
+/// \brief The \c MessageRendererImpl class is the actual implementation of
+/// \c MessageRenderer.
+///
+/// The implementation is hidden from applications.  We can refer to specific
+/// members of this class only within this file.
+///
 struct MessageRendererImpl {
+    /// \brief Constructor from an output buffer.
+    ///
+    /// \param buffer An \c OutputBuffer object to which wire format data is
+    /// written.
     MessageRendererImpl(OutputBuffer& buffer) :
         buffer_(buffer), nbuffer_(Name::MAX_WIRE) {}
+    /// The buffer that holds the entire DNS message.
     OutputBuffer& buffer_;
+    /// A local working buffer to convert each given name into wire format.
+    /// This could be a local variable of the \c writeName() method, but
+    /// we keep it in the class so that we can reuse it and avoid construction
+    /// overhead.
     OutputBuffer nbuffer_;
+    /// A set of compression pointers.
     std::set<NameCompressNode, NameCompare> nodeset_;
 };
 
-MessageRenderer::MessageRenderer(OutputBuffer& buffer)
-{
-    impl_ = new MessageRendererImpl(buffer);
-}
+MessageRenderer::MessageRenderer(OutputBuffer& buffer) :
+    impl_(new MessageRendererImpl(buffer))
+{}
 
 MessageRenderer::~MessageRenderer()
 {
@@ -120,6 +165,8 @@
     unsigned int i;
     std::set<NameCompressNode>::const_iterator n;
 
+    // Find the longest ancestor name in the rendered set that matches the
+    // given name.
     for (i = 0; i < impl_->nbuffer_.getLength(); i += impl_->nbuffer_[i] + 1) {
         // skip the trailing null label
         if (impl_->nbuffer_[i] == 0) {
@@ -133,22 +180,25 @@
         }
     }
 
+    // Record the current offset before extending the buffer.
     size_t offset = impl_->buffer_.getLength();
-    // write uncompress part...
+    // Write uncompress part...
     impl_->buffer_.writeData(impl_->nbuffer_.getData(),
                              compress ? i : impl_->nbuffer_.getLength());
     if (compress && n != impl_->nodeset_.end()) {
         // ...and compression pointer if available.
         uint16_t pointer = (*n).pos_;
-        pointer |= 0xc000;
+        pointer |= Name::COMPRESS_POINTER_MARK16;
         impl_->buffer_.writeUint16(pointer);
     }
 
+    // Finally, add to the set the newly rendered name and its ancestors that
+    // have not been in the set.
     for (unsigned int j = 0; j < i; j += impl_->nbuffer_[j] + 1) {
         if (impl_->nbuffer_[j] == 0) {
             continue;
         }
-        if (offset + j >= 0x4000) {
+        if (offset + j > Name::MAX_COMPRESS_POINTER) {
             break;
         }
         impl_->nodeset_.insert(NameCompressNode(impl_->buffer_, offset + j,

Modified: branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.h
==============================================================================
--- branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.h (original)
+++ branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.h Sat Dec 19 03:16:26 2009
@@ -24,10 +24,87 @@
 class Name;
 class MessageRendererImpl;
 
+///
+/// \brief The \c MessageRenderer class encapsulates implementation details
+/// of rendering a DNS message into a buffer in wire format.
+///
+/// In effect, it's simply responsible for name compression at least in the
+/// current implementation.  A \c MessageRenderer class object manages the
+/// positions of names rendered in a buffer and uses that information to render
+/// subsequent names with compression.
+///
+/// This class is mainly intended to be used as a helper for a more
+/// comprehensive \c Message class internally; normal applications won't have
+/// to care about this class.
+///
+/// A \c MessageRenderer class object is constructed with a \c OutputBuffer
+/// object, which is the buffer into which the rendered data will be written.
+/// Normally the buffer is expected to be empty on construction, but it doesn't
+/// have to be so; the \c MessageRenderer object will start rendering from the
+/// end of the buffer at the time of construction.  However, if the
+/// pre-existing portion of the buffer contains DNS names, these names won't
+/// be considered for name compression.
+///
+/// Once a \c MessageRenderer object is constructed with a buffer, it is
+/// generally expected that all rendering operations are performed via the
+/// \c MessageRenderer object.  If the application modifies the buffer in
+/// parallel with the \c MessageRenderer, the result will be undefined.
+///
+/// Note to developers: we introduced a separate class for name compression
+/// because previous benchmark with BIND9 showed compression affects overall
+/// response performance very much.  By having a separate class dedicated for
+/// this purpose, we'll be able to change the internal implementation of name
+/// compression in the future without affecting other part of the API and
+/// implementation.  For the same reason, we adopt the "pimpl" idiom in the
+/// class definition (i.e., using a pointer to a \c MessageRendererImpl class,
+/// which is defined with the class implementation, not in the header file):
+/// we may want to modify the compression implementation without modifying the
+/// header file thereby requesting rebuild the package.
+///
+/// Furthermore, we may eventually want to allow other developers to develop
+/// and use their own compression implementation.  Should such a case become
+/// realistic, we may want to make the \c MessageRendererImpl class an abstract
+/// base class and let concrete derived classes have their own implementations.
+/// At the moment we don't the strong need for it, so we rather avoid over
+/// abstraction and keep the definition simpler.
 class MessageRenderer {
 public:
+    ///
+    /// \name Constructors and Destructor
+    //@{
+    /// \brief Constructor from an output buffer.
+    ///
+    /// \param buffer An \c OutputBuffer object to which wire format data is
+    /// written.
     MessageRenderer(OutputBuffer& buffer);
+    /// \brief The default destructor.
+    ///
+    /// The destructor does nothing on the given \c buffer on construction;
+    /// in fact, it is expected that the user will use the resulting buffer
+    /// for some post rendering purposes (e.g., send the data to the network).
+    /// It's user's responsibility to do any necessary cleanup for the
+    /// \c buffer.
     ~MessageRenderer();
+    //@}
+
+    ///
+    /// \name Rendering Methods
+    ///
+    //@{
+    /// \brief Write a \c Name object into the internal buffer in wire format,
+    /// with or without name compression.
+    ///
+    /// If the optional parameter \c compress is \c true, this method tries to
+    /// compress the \c name if possible, searching the entire message that has
+    /// been rendered.  Otherwise name compression is omitted.  Its default
+    /// value is \c true.
+    ///
+    /// Note: even if \c compress is \c true, the position of the \c name (and
+    /// possibly its ancestor names) in the message is recorded and may be used
+    /// for compressing subsequent names.
+    ///
+    /// \param name A \c Name object to be written.
+    /// \param compress A boolean indicating whether to enable name compression.
     void writeName(const Name& name, bool compress = true);
 private:
     MessageRendererImpl* impl_;




More information about the bind10-changes mailing list