LogCabin
Tree/Tree.h
Go to the documentation of this file.
00001 /* Copyright (c) 2012 Stanford University
00002  * Copyright (c) 2014 Diego Ongaro
00003  *
00004  * Permission to use, copy, modify, and distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
00009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
00011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 #include <map>
00018 #include <string>
00019 #include <vector>
00020 
00021 #include "Core/ProtoBuf.h"
00022 
00023 #ifndef LOGCABIN_TREE_TREE_H
00024 #define LOGCABIN_TREE_TREE_H
00025 
00026 namespace LogCabin {
00027 
00028 // forward declaration
00029 namespace Protocol {
00030 class ServerStats_Tree;
00031 }
00032 
00033 namespace Tree {
00034 
00035 /**
00036  * Status codes returned by Tree operations.
00037  */
00038 enum class Status {
00039 
00040     /**
00041      * The operation completed successfully.
00042      */
00043     OK = 0,
00044 
00045     /**
00046      * If an argument is malformed (for example, a path that does not start
00047      * with a slash).
00048      */
00049     INVALID_ARGUMENT = 1,
00050 
00051     /**
00052      * If a file or directory that is required for the operation does not
00053      * exist.
00054      */
00055     LOOKUP_ERROR = 2,
00056 
00057     /**
00058      * If a directory exists where a file is required or a file exists where
00059      * a directory is required. 
00060      */
00061     TYPE_ERROR = 3,
00062 
00063     /**
00064      * A predicate on an operation was not satisfied.
00065      */
00066     CONDITION_NOT_MET = 4,
00067 };
00068 
00069 /**
00070  * Print a status code to a stream.
00071  */
00072 std::ostream&
00073 operator<<(std::ostream& os, Status status);
00074 
00075 /**
00076  * Returned by Tree operations; contain a status code and an error message.
00077  */
00078 struct Result {
00079     /**
00080      * Default constructor. Sets status to OK and error to the empty string.
00081      */
00082     Result();
00083     /**
00084      * A code for whether an operation succeeded or why it did not. This is
00085      * meant to be used programmatically.
00086      */
00087     Status status;
00088     /**
00089      * If status is not OK, this is a human-readable message describing what
00090      * went wrong.
00091      */
00092     std::string error;
00093 };
00094 
00095 namespace Internal {
00096 
00097 /**
00098  * A leaf object in the Tree; stores an opaque blob of data.
00099  */
00100 class File {
00101   public:
00102     /// Default constructor.
00103     File();
00104     /**
00105      * Write the file to the stream.
00106      */
00107     void dumpSnapshot(Core::ProtoBuf::OutputStream& stream) const;
00108     /**
00109      * Load the file from the stream.
00110      */
00111     void loadSnapshot(Core::ProtoBuf::InputStream& stream);
00112     /**
00113      * Opaque data stored in the File.
00114      */
00115     std::string contents;
00116 };
00117 
00118 /**
00119  * An interior object in the Tree; stores other Directories and Files.
00120  * Pointers returned by this class are valid until the File or Directory they
00121  * refer to is removed.
00122  */
00123 class Directory {
00124   public:
00125     /// Default constructor.
00126     Directory();
00127 
00128     /**
00129      * List the contents of the directory.
00130      * \return
00131      *      The names of the directories and files that this directory
00132      *      immediately contains. The names of directories in this listing will
00133      *      have a trailing slash. The order is first directories (sorted
00134      *      lexicographically), then files (sorted lexicographically).
00135      */
00136     std::vector<std::string> getChildren() const;
00137 
00138     /**
00139      * Find the child directory by the given name.
00140      * \param name
00141      *      Must not contain a trailing slash.
00142      * \return
00143      *      The directory by the given name, or
00144      *      NULL if it is not found or a file exists by that name.
00145      */
00146     Directory* lookupDirectory(const std::string& name);
00147     /**
00148      * Find the child directory by the given name (const version).
00149      * \copydetails lookupDirectory
00150      */
00151     const Directory* lookupDirectory(const std::string& name) const;
00152     /**
00153      * Find the child directory by the given name, or create it if it doesn't
00154      * exist.
00155      * \param name
00156      *      Must not contain a trailing slash.
00157      * \return
00158      *      The directory by the given name, or
00159      *      NULL if a file exists by that name.
00160      */
00161     Directory* makeDirectory(const std::string& name);
00162     /**
00163      * Remove the child directory by the given name, if any. This will remove
00164      * all the contents of the directory as well.
00165      * \param name
00166      *      Must not contain a trailing slash.
00167      */
00168     void removeDirectory(const std::string& name);
00169 
00170     /**
00171      * Find the child file by the given name.
00172      * \param name
00173      *      Must not contain a trailing slash.
00174      * \return
00175      *      The file by the given name, or
00176      *      NULL if it is not found or a directory exists by that name.
00177      */
00178     File* lookupFile(const std::string& name);
00179     /**
00180      * Find the child file by the given name (const version).
00181      * \copydetails lookupFile
00182      */
00183     const File* lookupFile(const std::string& name) const;
00184     /**
00185      * Find the child file by the given name, or create it if it doesn't exist.
00186      * \param name
00187      *      Must not contain a trailing slash.
00188      * \return
00189      *      The file by the given name, or
00190      *      NULL if a directory exists by that name.
00191      */
00192     File* makeFile(const std::string& name);
00193     /**
00194      * Remove the child file by the given name, if any.
00195      * \param name
00196      *      Must not contain a trailing slash.
00197      * \return
00198      *      True if child file removed, false if no such file existed. This is
00199      *      mostly useful for counting statistics.
00200      */
00201     bool removeFile(const std::string& name);
00202 
00203     /**
00204      * Write the directory and its children to the stream.
00205      */
00206     void dumpSnapshot(Core::ProtoBuf::OutputStream& stream) const;
00207     /**
00208      * Load the directory and its children from the stream.
00209      */
00210     void loadSnapshot(Core::ProtoBuf::InputStream& stream);
00211 
00212   private:
00213     /**
00214      * Map from names of child directories (without trailing slashes) to the
00215      * Directory objects.
00216      */
00217     std::map<std::string, Directory> directories;
00218     /**
00219      * Map from names of child files to the File objects.
00220      */
00221     std::map<std::string, File> files;
00222 };
00223 
00224 /**
00225  * This is used by Tree to parse symbolic paths into their components.
00226  */
00227 class Path {
00228   public:
00229     /**
00230      * Constructor.
00231      * \param symbolic
00232      *      A path delimited by slashes. This must begin with a slash.
00233      *      (It should not include "/root" to arrive at the root directory.)
00234      * \warning
00235      *      The caller must check "result" to see if the path was parsed
00236      *      successfully.
00237      */
00238     explicit Path(const std::string& symbolic);
00239 
00240     /**
00241      * Used to generate error messages during path lookup.
00242      * \param end
00243      *      The last component of 'parents' to include in the returned string;
00244      *      this is typically the component that caused an error in path
00245      *      traversal.
00246      * \return
00247      *      The prefix of 'parents' up to and including the given end position.
00248      *      This is returned as a slash-delimited string not including "/root".
00249      */
00250     std::string
00251     parentsThrough(std::vector<std::string>::const_iterator end) const;
00252 
00253   public:
00254     /**
00255      * Status and error message from the constructor. Possible errors are:
00256      * - INVALID_ARGUMENT if path is malformed.
00257      */
00258     Result result;
00259 
00260     /**
00261      * The exact argument given to the constructor.
00262      */
00263     std::string symbolic;
00264     /**
00265      * The directories needed to traverse to get to the target.
00266      * This usually begins with "root" to get from the super root to the root
00267      * directory, then includes the components of the symbolic path up to but
00268      * not including the target. If the symbolic path is "/", this will be
00269      * empty.
00270      */
00271     std::vector<std::string> parents;
00272     /**
00273      * The final component of the path.
00274      * This is usually at the end of the symbolic path. If the symbolic path is
00275      * "/", this will be "root", used to get from the super root to the root
00276      * directory.
00277      */
00278     std::string target;
00279 };
00280 
00281 } // LogCabin::Tree::Internal
00282 
00283 /**
00284  * This is an in-memory, hierarchical key-value store.
00285  * TODO(ongaro): Document how this fits into the rest of the system.
00286  */
00287 class Tree {
00288   public:
00289     /**
00290      * Constructor.
00291      */
00292     Tree();
00293 
00294     /**
00295      * Write the tree to the given stream.
00296      */
00297     void dumpSnapshot(Core::ProtoBuf::OutputStream& stream) const;
00298 
00299     /**
00300      * Load the tree from the given stream.
00301      * \warning
00302      *      This will blow away any existing files and directories.
00303      */
00304     void loadSnapshot(Core::ProtoBuf::InputStream& stream);
00305 
00306     /**
00307      * Verify that the file at path has the given contents.
00308      * \param path
00309      *      The path to the file that must have the contents specified in
00310      *      'contents'.
00311      * \param contents
00312      *      The contents that the file specified by 'path' should have for an
00313      *      OK response. An OK response is also returned if 'contents' is the
00314      *      empty string and the file specified by 'path' does not exist.
00315      * \return
00316      *      Status and error message. Possible errors are:
00317      *       - CONDITION_NOT_MET upon any error.
00318      */
00319     Result
00320     checkCondition(const std::string& path,
00321                    const std::string& contents) const;
00322 
00323     /**
00324      * Make sure a directory exists at the given path.
00325      * Create parent directories listed in path as necessary.
00326      * \param path
00327      *      The path where there should be a directory after this call.
00328      * \return
00329      *      Status and error message. Possible errors are:
00330      *       - INVALID_ARGUMENT if path is malformed.
00331      *       - TYPE_ERROR if a parent of path is a file.
00332      *       - TYPE_ERROR if path exists but is a file.
00333      */
00334     Result
00335     makeDirectory(const std::string& path);
00336 
00337     /**
00338      * List the contents of a directory.
00339      * \param path
00340      *      The directory whose direct children to list.
00341      * \param[out] children
00342      *      This will be replaced by a listing of the names of the directories
00343      *      and files that the directory at 'path' immediately contains. The
00344      *      names of directories in this listing will have a trailing slash.
00345      *      The order is first directories (sorted lexicographically), then
00346      *      files (sorted lexicographically).
00347      * \return
00348      *      Status and error message. Possible errors are:
00349      *       - INVALID_ARGUMENT if path is malformed.
00350      *       - LOOKUP_ERROR if a parent of path does not exist.
00351      *       - LOOKUP_ERROR if path does not exist.
00352      *       - TYPE_ERROR if a parent of path is a file.
00353      *       - TYPE_ERROR if path exists but is a file.
00354      */
00355     Result
00356     listDirectory(const std::string& path,
00357                   std::vector<std::string>& children) const;
00358 
00359     /**
00360      * Make sure a directory does not exist.
00361      * Also removes all direct and indirect children of the directory.
00362      *
00363      * If called with the root directory, this will remove all descendants but
00364      * not actually remove the root directory; it will still return status OK.
00365      *
00366      * \param path
00367      *      The path where there should not be a directory after this call.
00368      * \return
00369      *      Status and error message. Possible errors are:
00370      *       - INVALID_ARGUMENT if path is malformed.
00371      *       - TYPE_ERROR if a parent of path is a file.
00372      *       - TYPE_ERROR if path exists but is a file.
00373      */
00374     Result
00375     removeDirectory(const std::string& path);
00376 
00377     /**
00378      * Set the value of a file.
00379      * \param path
00380      *      The path where there should be a file with the given contents after
00381      *      this call.
00382      * \param contents
00383      *      The new value associated with the file.
00384      * \return
00385      *      Status and error message. Possible errors are:
00386      *       - INVALID_ARGUMENT if path is malformed.
00387      *       - INVALID_ARGUMENT if contents are too large to fit in a file.
00388      *       - LOOKUP_ERROR if a parent of path does not exist.
00389      *       - TYPE_ERROR if a parent of path is a file.
00390      *       - TYPE_ERROR if path exists but is a directory.
00391      */
00392     Result
00393     write(const std::string& path, const std::string& contents);
00394 
00395     /**
00396      * Get the value of a file.
00397      * \param path
00398      *      The path of the file whose contents to read.
00399      * \param contents
00400      *      The current value associated with the file.
00401      * \return
00402      *      Status and error message. Possible errors are:
00403      *       - INVALID_ARGUMENT if path is malformed.
00404      *       - LOOKUP_ERROR if a parent of path does not exist.
00405      *       - LOOKUP_ERROR if path does not exist.
00406      *       - TYPE_ERROR if a parent of path is a file.
00407      *       - TYPE_ERROR if path is a directory.
00408      */
00409     Result
00410     read(const std::string& path, std::string& contents) const;
00411 
00412     /**
00413      * Make sure a file does not exist.
00414      * \param path
00415      *      The path where there should not be a file after this call.
00416      * \return
00417      *      Status and error message. Possible errors are:
00418      *       - INVALID_ARGUMENT if path is malformed.
00419      *       - TYPE_ERROR if a parent of path is a file.
00420      *       - TYPE_ERROR if path exists but is a directory.
00421      */
00422     Result
00423     removeFile(const std::string& path);
00424 
00425     /**
00426      * Add metrics about the tree to the given structure.
00427      */
00428     void
00429     updateServerStats(Protocol::ServerStats_Tree& tstats) const;
00430 
00431   private:
00432     /**
00433      * Resolve the final next-to-last component of the given path (the target's
00434      * parent).
00435      * \param[in] path
00436      *      The path whose parent directory to find.
00437      * \param[out] parent
00438      *      Upon successful return, points to the target's parent directory.
00439      * \return
00440      *      Status and error message. Possible errors are:
00441      *       - LOOKUP_ERROR if a parent of path does not exist.
00442      *       - TYPE_ERROR if a parent of path is a file.
00443      */
00444     Result
00445     normalLookup(const Internal::Path& path,
00446                  Internal::Directory** parent);
00447 
00448     /**
00449      * Resolve the final next-to-last component of the given path (the target's
00450      * parent) -- const version.
00451      * \copydetails normalLookup
00452      */
00453     Result
00454     normalLookup(const Internal::Path& path,
00455                  const Internal::Directory** parent) const;
00456 
00457     /**
00458      * Like normalLookup but creates parent directories as necessary.
00459      * \param[in] path
00460      *      The path whose parent directory to find.
00461      * \param[out] parent
00462      *      Upon successful return, points to the target's parent directory.
00463      * \return
00464      *      Status and error message. Possible errors are:
00465      *       - TYPE_ERROR if a parent of path is a file.
00466      */
00467     Result
00468     mkdirLookup(const Internal::Path& path, Internal::Directory** parent);
00469 
00470     /**
00471      * This directory contains the root directory. The super root has a single
00472      * child directory named "root", and the rest of the tree lies below
00473      * "root". This is just an implementation detail; this class prepends
00474      * "/root" to every path provided by the caller.
00475      *
00476      * This removes a lot of special-case branches because every operation now
00477      * has a name of a target within a parent directory -- even those operating
00478      * on the root directory.
00479      */
00480     Internal::Directory superRoot;
00481 
00482     // Server stats collected in updateServerStats.
00483     // Note that when a condition fails, the operation is not invoked,
00484     // so operations whose conditions fail are not counted as 'Attempted'.
00485     mutable uint64_t numConditionsChecked;
00486     mutable uint64_t numConditionsFailed;
00487     uint64_t numMakeDirectoryAttempted;
00488     uint64_t numMakeDirectorySuccess;
00489     mutable uint64_t numListDirectoryAttempted;
00490     mutable uint64_t numListDirectorySuccess;
00491     uint64_t numRemoveDirectoryAttempted;
00492     uint64_t numRemoveDirectoryParentNotFound;
00493     uint64_t numRemoveDirectoryTargetNotFound;
00494     uint64_t numRemoveDirectoryDone;
00495     uint64_t numRemoveDirectorySuccess;
00496     uint64_t numWriteAttempted;
00497     uint64_t numWriteSuccess;
00498     mutable uint64_t numReadAttempted;
00499     mutable uint64_t numReadSuccess;
00500     uint64_t numRemoveFileAttempted;
00501     uint64_t numRemoveFileParentNotFound;
00502     uint64_t numRemoveFileTargetNotFound;
00503     uint64_t numRemoveFileDone;
00504     uint64_t numRemoveFileSuccess;
00505 };
00506 
00507 
00508 } // namespace LogCabin::Tree
00509 } // namespace LogCabin
00510 
00511 #endif // LOGCABIN_TREE_TREE_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines