Browse Source

[2097] overall documentation update

JINMEI Tatuya 12 years ago
parent
commit
7c0e1396fa
2 changed files with 222 additions and 19 deletions
  1. 3 6
      src/lib/datasrc/memory/rdataset.cc
  2. 219 13
      src/lib/datasrc/memory/rdataset.h

+ 3 - 6
src/lib/datasrc/memory/rdataset.cc

@@ -65,11 +65,8 @@ RdataSet::create(util::MemorySegment& mem_sgmt, RdataEncoder& encoder,
     if (sig_rrset && sig_rrset->getRdataCount() == 0) {
         isc_throw(BadValue, "Empty SIG RRset");
     }
-    if (rrset && sig_rrset) {
-        if (rrset->getClass() != sig_rrset->getClass()) {
-            isc_throw(BadValue,
-                      "RR class doesn't match between RRset and RRSIG");
-        }
+    if (rrset && sig_rrset && rrset->getClass() != sig_rrset->getClass()) {
+        isc_throw(BadValue, "RR class doesn't match between RRset and RRSIG");
     }
 
     // Check assumptions on the number of RDATAs
@@ -135,7 +132,7 @@ RdataSet::destroy(util::MemorySegment& mem_sgmt, RRClass rrclass,
                     rdataset->getRdataCount(),
                     rdataset->getSigRdataCount()).getSize();
     const size_t ext_rrsig_count_len =
-        rdataset->sig_rdata_count_ >= MANY_RRSIG_COUNT ? sizeof(uint16_t) : 0;
+        rdataset->sig_rdata_count_ == MANY_RRSIG_COUNT ? sizeof(uint16_t) : 0;
     rdataset->~RdataSet();
     mem_sgmt.deallocate(rdataset,
                         sizeof(RdataSet) + ext_rrsig_count_len + data_len);

+ 219 - 13
src/lib/datasrc/memory/rdataset.h

@@ -41,12 +41,155 @@ public:
         Exception(file, line, what) {}
 };
 
+/// \brief Memory-efficient representation of RRset data with RRSIGs.
+///
+/// This class provides memory-efficient and lightweight interface to various
+/// attributes of an RRset, which may or may not be signed with RRSIGs.
+///
+/// This class is primarily intended to be used in the in-memory data source
+/// implementation, and is not supposed to be used by general applications.
+/// The major design goals is to keep required memory footprint for the given
+/// amount of data as small as possible, while providing reasonably efficient
+/// interface to examine the data, focusing on zone lookup and DNS message
+/// rendering.
+///
+/// It encodes a specific set of RRset and (when signed) its RRSIGs, excluding
+/// the owner name and the RR class.  The owner name is supposed to be
+/// maintained by the application outside this class (the intended place to
+/// store this information is a \c DomainTree node, although this
+/// implementation does not rely on that intent).  The RR class must be the
+/// same in a single zone, and it's simply a waste if we have it with each
+/// RRset.  The RR class information is therefore expected to be maintained
+/// outside this class.
+///
+/// This class imposes some limitations on the number of RDATAs of the RRset
+/// and RRSIG: a (non RRSIG) RRset containing more than 8191 (2^13 - 1)
+/// or an RRSIG containing more than 65535 (2^16 - 1) RDATAs cannot be
+/// maintained in this class.  The former restriction comes from the
+/// following observation: any RR in wire format in a DNS message must at
+/// least contain 10 bytes of data (for RR type, class, TTL and RDATA length),
+/// and since a valid DNS message must not be larger than 65535 bytes,
+/// no valid DNS response can contain more than 6554 RRs.  So, in practice,
+/// it should be reasonable even if we reject very large RRsets that would
+/// not fit in a DNS message.  For the same reason we restrict the number of
+/// RRSIGs, although due to internal implementation details the limitation
+/// is more relaxed for RRSIGs.
+///
+/// \note (This is pure implementation details) By limiting the number of
+/// RDATAs so it will fit in a 13-bit integer, we can use 3 more bits in a
+/// 2-byte integer for other purposes.  We use this additional field to
+/// represent the number of RRSIGs up to 6, while using the value of 7 to mean
+/// there are more than 6 RRSIGs.  In the vast majority of real world
+/// deployment, an RRset should normally have only a few RRSIGs, and 6 should
+/// normally be more than sufficient.  So we can cover most practical cases
+/// regarding the number of records with this 2-byte field.
+///
+/// A set of objects of this class (which would be \c RdataSets of various
+/// types of the same owner name) will often be maintained in a single linked
+/// list.  The class has a member variable to make the link.
+///
+/// This class is designed so an instance can be stored in a shared
+/// memory region.  So it only contains straightforward data (e.g., it
+/// doesn't hold a pointer to an object of some base class that
+/// contains virtual methods), and the pointer member (see the
+/// previous paragraph) is represented as an offset pointer.  For the
+/// same reason this class should never have virtual methods (and as a
+/// result, should never be inherited in practice).  When this class
+/// is extended these properties must be preserved.
+///
+/// The \c RdataSet class itself only contains a subset of attributes that
+/// it is conceptually expected to contain.  The rest of the attributes
+/// are encoded in a consecutive memory region immediately following the main
+/// \c RdataSet object.  The memory layout would be as follows:
+/// \verbatim
+/// RdataSet object
+/// (optional) uint16_t: number of RRSIGs, if it's larger than 6 (see above)
+/// encoded RDATA (generated by RdataEncoder) \endverbatim
+///
+/// This is shown here only for reference purposes.  The application must not
+/// assume any particular format of data in this region directly; it must
+/// get access to it via public interfaces provided in the main \c RdataSet
+/// class.
 class RdataSet {
 public:
+    /// \brief Allocate and construct \c RdataSet
+    ///
+    /// This static method allocates memory for a new \c RdataSet
+    /// object for the set of an RRset and (if it's supposed to be signed)
+    /// RRSIG from the given memory segment, constructs the object, and
+    /// returns a pointer to it.
+    ///
+    /// Normally the (non RRSIG) RRset is given (\c rrset is not NULL) while
+    /// its RRSIG (\c sig_rrset) may or may not be provided.  But it's also
+    /// expected that in some rare (mostly broken) cases there can be an RRSIG
+    /// RR in a zone without having the covered RRset in the zone.  To handle
+    /// such cases, this class allows to only hold RRSIG, in which case
+    /// \c rrset can be NULL.  At least \c rrset or \c sig_rrset must be
+    /// non NULL, however.  Also, if non NULL, the RRset must not be empty,
+    /// that is, it must contain at least one RDATA.
+    ///
+    /// The RR type of \c rrset must not be RRSIG; the RR type of \c sig_rrset
+    /// must be RRSIG.
+    ///
+    /// When both \c rrset and \c sig_rrset are provided (both are non
+    /// NULL), the latter must validly cover the former: the RR class
+    /// must be identical; the type covered field of any RDATA of \c
+    /// sig_rrset must be identical to the RR type of \c rrset.  The owner
+    /// name of these RRsets must also be identical, but this implementation
+    /// doesn't require it because \c RdataSet itself does not rely on the
+    /// owner name, and it should be pretty likely that this condition is met
+    /// in the context where this class is used (and, name comparison is
+    /// relatively expensive, and if we end up comparing them twice the
+    /// overhead can be non negligible).
+    ///
+    /// If any of the above conditions isn't met, an isc::BadValue exception
+    /// will be thrown; basically, there should be a bug in the caller if this
+    /// happens.
+    ///
+    /// Due to implementation limitations, this class cannot contain more than
+    /// 8191 RDATAs for the non RRISG RRset; also, it cannot contain more than
+    /// 65535 RRSIGs.  If the given RRset(s) fail to meet this condition,
+    /// an \c RdataSetError exception will be thrown.
+    ///
+    /// \throw isc::BadValue Given RRset(s) are invalid (see the description)
+    /// \throw RdataSetError Number of RDATAs exceed the limits
+    /// \throw std::bad_alloc Memory allocation fails.
+    ///
+    /// \param mem_sgmt A \c MemorySegment from which memory for the new
+    /// \c RdataSet is allocated.
+    /// \param encoder The RDATA encoder to encode \c rrset and \c sig_rrset
+    /// with the \c RdataSet to be created.
+    /// \param rrset A (non RRSIG) RRset from which the \c RdataSet is to be
+    /// created.  Can be NULL if sig_rrset is not.
+    /// \param sig_rrset An RRSIG RRset from which the \c RdataSet is to be
+    /// created.  Can be NULL if rrset is not.
+    ///
+    /// \return A pointer to the created \c RdataSet.
     static RdataSet* create(util::MemorySegment& mem_sgmt,
                             RdataEncoder& encoder,
                             dns::ConstRRsetPtr rrset,
                             dns::ConstRRsetPtr sig_rrset);
+
+    /// \brief Destruct and deallocate \c RdataSet
+    ///
+    /// Note that this method needs to know the expected RR class of the
+    /// \c RdataSet.  This is because the destruction may depend on the
+    /// internal data encoding that only \c RdataEncoder and \c RdataReader
+    /// know, and they need to know the corresponding RR class and type to
+    /// identify the internal data representation.  Since \c RdataSet itself
+    /// does not hold the class information, the caller needs to provide it.
+    /// Obviously, this RR class must be identical to the RR class of \c rrset
+    /// (when given) or of \c sig_rrset (when \c rrset isn't given) at the
+    /// \c create() time.
+    ///
+    /// \throw none
+    ///
+    /// \param mem_sgmt The \c MemorySegment that allocated memory for
+    /// \c node.
+    /// \param rrclass The RR class of the \c RdataSet to be destroyed.
+    /// \param rdataset A non NULL pointer to a valid \c RdataSet object
+    /// that was originally created by the \c create() method (the behavior
+    /// is undefined if this condition isn't met).
     static void destroy(util::MemorySegment& mem_sgmt, dns::RRClass rrclass,
                         RdataSet* rdataset);
 
@@ -56,19 +199,38 @@ public:
     // Note: the size and order of the members are carefully chosen to
     // maximize efficiency.  Don't change them unless there's strong reason
     // for that and the consequences are considered.
+    // For convenience (and since this class is mostly intended to be an
+    // internal definition for the in-memory data source implementation),
+    // we allow the application to get access to some members directly.
+    // Some others require some conversion to use in a meaningful way,
+    // for which we force the application to use accessor methods in order
+    // to prevent misuse.
+
+    RdataSetPtr next; ///< Pointer to the next \c RdataSet (when linked)
+    const dns::RRType type;     ///< The RR type of the \c RdataSet
 
-    RdataSetPtr next;
-    const dns::RRType type;
 private:
-    const uint16_t sig_rdata_count_ : 3;
-    const uint16_t rdata_count_ : 13;
-    const uint32_t ttl_;       ///< TTL of the RdataSet, net byte order
+    const uint16_t sig_rdata_count_ : 3; // # of RRSIGs, up to 6 (7 means many)
+    const uint16_t rdata_count_ : 13; // # of RDATAs, up to 8191
+    const uint32_t ttl_;       // TTL of the RdataSet, net byte order
 
+    // Max number of normal RDATAs that can be stored in \c RdataSet.
+    // It's 2^13 - 1 = 8191.
     static const size_t MAX_RDATA_COUNT = (1 << 13) - 1;
+
+    // Max number of RRSIGs that can be stored in \c RdataSet.
+    // It's 2^16 - 1 = 65535.
     static const size_t MAX_RRSIG_COUNT = (1 << 16) - 1;
+
+    // Indicate the \c RdataSet contains many RRSIGs that require an additional
+    // field for the real number of RRSIGs.  It's 2^3 - 1 = 7.
     static const size_t MANY_RRSIG_COUNT = (1 << 3) - 1;
+
 public:
+    /// \brief Return the number of RDATAs stored in the \c RdataSet.
     size_t getRdataCount() const { return (rdata_count_); }
+
+    /// \brief Return the number of RRSIG RDATAs stored in the \c RdataSet.
     size_t getSigRdataCount() const {
         if (sig_rdata_count_ < MANY_RRSIG_COUNT) {
             return (sig_rdata_count_);
@@ -76,21 +238,40 @@ public:
             return (*getExtSIGCountBuf());
         }
     }
+
+    /// \brief Return a pointer to the TTL data of the \c RdataSet.
+    ///
+    /// The returned pointer points to a memory region that is valid at least
+    /// for 32 bits, storing the TTL of the \c RdataSet in the network byte
+    /// order.  It returns opaque data to make it clear that unless the wire
+    /// format data is necessary (e.g., when rendering it in a DNS message),
+    /// it should be converted to, e.g., an \c RRTTL object explicitly.
+    ///
+    /// \throw none
     const void* getTTLData() const { return (&ttl_); }
-    void* getDataBuf() {
-        return (getDataBuf<void, RdataSet>(this));
-    }
+
+    /// \brief Accessor to the memory region for encoded RDATAs.
+    ///
+    /// The only valid usage of the returned pointer is to pass it to
+    /// the constructor of \c RdataReader.
+    ///
+    /// \throw none
     const void* getDataBuf() const {
         return (getDataBuf<const void, const RdataSet>(this));
     }
 
 private:
-    uint16_t* getExtSIGCountBuf() {
-        return (reinterpret_cast<uint16_t*>(this + 1));
-    }
-    const uint16_t* getExtSIGCountBuf() const {
-        return (reinterpret_cast<const uint16_t*>(this + 1));
+    /// \brief Accessor to the memory region for encoded RDATAs, mutable
+    /// version.
+    ///
+    /// This version is only used within the class implementation, so it's
+    /// defined as private.
+    void* getDataBuf() {
+        return (getDataBuf<void, RdataSet>(this));
     }
+
+    // Implementation of getDataBuf().  Templated to unify the mutable and
+    // immutable versions.
     template <typename RetType, typename ThisType>
     static RetType* getDataBuf(ThisType* rdataset) {
         if (rdataset->sig_rdata_count_ < MANY_RRSIG_COUNT) {
@@ -100,8 +281,33 @@ private:
         }
     }
 
+    /// \brief Accessor to the memory region for the RRSIG count field for
+    /// a large number of RRSIGs.
+    ///
+    /// These are used only internally and defined as private.
+    const uint16_t* getExtSIGCountBuf() const {
+        return (reinterpret_cast<const uint16_t*>(this + 1));
+    }
+    uint16_t* getExtSIGCountBuf() {
+        return (reinterpret_cast<uint16_t*>(this + 1));
+    }
+
+    /// \brief The constructor.
+    ///
+    /// An object of this class is always expected to be created by the
+    /// allocator (\c create()), so the constructor is hidden as private.
+    ///
+    /// It never throws an exception.
     RdataSet(dns::RRType type, size_t rdata_count, size_t sig_rdata_count,
              dns::RRTTL ttl);
+
+    /// \brief The destructor.
+    ///
+    /// An object of this class is always expected to be destroyed explicitly
+    /// by \c destroy(), so the destructor is hidden as private.
+    ///
+    /// This currently does nothing, but is explicitly defined to clarify
+    /// it's intentionally defined as private.
     ~RdataSet() {}
 };