From: Adam Crume Date: Thu, 11 Sep 2014 17:44:59 +0000 (-0700) Subject: rbd-replay: Add code documentation X-Git-Tag: v0.88~176^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=f54d5c7b2f5d2904e10636b126dccb6db2d854d9;p=ceph.git rbd-replay: Add code documentation Signed-off-by: Adam Crume --- diff --git a/src/rbd_replay/BoundedBuffer.hpp b/src/rbd_replay/BoundedBuffer.hpp index 540fd317e216..e4df483c1f67 100644 --- a/src/rbd_replay/BoundedBuffer.hpp +++ b/src/rbd_replay/BoundedBuffer.hpp @@ -9,7 +9,10 @@ #include #include -// Taken from http://www.boost.org/doc/libs/1_55_0/libs/circular_buffer/example/circular_buffer_bound_example.cpp +/** + Blocking, fixed-capacity, thread-safe FIFO queue useful for communicating between threads. + This code was taken from the Boost docs: http://www.boost.org/doc/libs/1_55_0/libs/circular_buffer/example/circular_buffer_bound_example.cpp + */ template class BoundedBuffer { public: @@ -21,6 +24,10 @@ public: explicit BoundedBuffer(size_type capacity) : m_unread(0), m_container(capacity) { } + /** + Inserts an element into the queue. + Blocks if the queue is full. + */ void push_front(typename boost::call_traits::param_type item) { // `param_type` represents the "best" way to pass a parameter of type `value_type` to a method. boost::mutex::scoped_lock lock(m_mutex); @@ -31,6 +38,10 @@ public: m_not_empty.notify_one(); } + /** + Removes an element from the queue. + Blocks if the queue is empty. + */ void pop_back(value_type* pItem) { boost::mutex::scoped_lock lock(m_mutex); m_not_empty.wait(lock, boost::bind(&BoundedBuffer::is_not_empty, this)); diff --git a/src/rbd_replay/Deser.hpp b/src/rbd_replay/Deser.hpp index d5fad5ae6650..b466acec6628 100644 --- a/src/rbd_replay/Deser.hpp +++ b/src/rbd_replay/Deser.hpp @@ -20,6 +20,11 @@ namespace rbd_replay { +/** + Helper for deserializing data in an architecture-indepdendent way. + Everything is read big-endian. + @see Ser +*/ class Deser { public: Deser(std::istream &in); diff --git a/src/rbd_replay/ImageNameMap.hpp b/src/rbd_replay/ImageNameMap.hpp index 00de76552cdf..45cdaf686947 100644 --- a/src/rbd_replay/ImageNameMap.hpp +++ b/src/rbd_replay/ImageNameMap.hpp @@ -21,14 +21,28 @@ namespace rbd_replay { +/** + Maps image names. + */ class ImageNameMap { public: typedef std::pair Mapping; + /** + Parses a mapping. + If parsing fails, the contents of \c mapping are undefined. + @param[in] mapping_string string representation of the mapping + @param[out] mapping stores the parsed mapping + @retval true parsing was successful + */ bool parse_mapping(std::string mapping_string, Mapping *mapping) const; void add_mapping(const Mapping& mapping); + /** + Maps an image name. + If no mapping matches the name, it is returned unmodified. + */ rbd_loc map(const rbd_loc& name) const; private: diff --git a/src/rbd_replay/PendingIO.cc b/src/rbd_replay/PendingIO.cc index 6c41001e11f0..bbf0a204c210 100644 --- a/src/rbd_replay/PendingIO.cc +++ b/src/rbd_replay/PendingIO.cc @@ -20,7 +20,7 @@ using namespace std; using namespace rbd_replay; extern "C" -void pending_io_callback(librbd::completion_t cb, void *arg) { +void rbd_replay_pending_io_callback(librbd::completion_t cb, void *arg) { PendingIO *io = static_cast(arg); io->completed(cb); } @@ -28,7 +28,7 @@ void pending_io_callback(librbd::completion_t cb, void *arg) { PendingIO::PendingIO(action_id_t id, ActionCtx &worker) : m_id(id), - m_completion(new librbd::RBD::AioCompletion(this, pending_io_callback)), + m_completion(new librbd::RBD::AioCompletion(this, rbd_replay_pending_io_callback)), m_worker(worker) { } diff --git a/src/rbd_replay/PendingIO.hpp b/src/rbd_replay/PendingIO.hpp index 3f0120744e9e..3942d5f6fd9d 100644 --- a/src/rbd_replay/PendingIO.hpp +++ b/src/rbd_replay/PendingIO.hpp @@ -18,8 +18,15 @@ #include #include "actions.hpp" +/// Do not call outside of rbd_replay::PendingIO. +extern "C" +void rbd_replay_pending_io_callback(librbd::completion_t cb, void *arg); + namespace rbd_replay { +/** + A PendingIO is an I/O operation that has been started but not completed. +*/ class PendingIO : public boost::enable_shared_from_this { public: typedef boost::shared_ptr ptr; @@ -29,8 +36,6 @@ public: ~PendingIO(); - void completed(librbd::completion_t cb); - action_id_t id() const { return m_id; } @@ -44,6 +49,10 @@ public: } private: + void completed(librbd::completion_t cb); + + friend void ::rbd_replay_pending_io_callback(librbd::completion_t cb, void *arg); + const action_id_t m_id; ceph::bufferlist m_bl; librbd::RBD::AioCompletion *m_completion; diff --git a/src/rbd_replay/Replayer.hpp b/src/rbd_replay/Replayer.hpp index 1cbecc2fe7a3..538e7fddd4df 100644 --- a/src/rbd_replay/Replayer.hpp +++ b/src/rbd_replay/Replayer.hpp @@ -25,13 +25,16 @@ namespace rbd_replay { class Replayer; +/** + Performs Actions within a single thread. + */ class Worker : public ActionCtx { public: explicit Worker(Replayer &replayer); void start(); - // Should only be called by StopThreadAction + /// Should only be called by StopThreadAction void stop(); void join(); @@ -123,7 +126,7 @@ public: private: struct action_tracker_d { - // Maps an action ID to the time the action completed + /// Maps an action ID to the time the action completed std::map actions; boost::shared_mutex mutex; boost::condition condition; @@ -133,8 +136,9 @@ private: action_tracker_d &tracker_for(action_id_t id); - // Disallow assignment and copying + /// Disallow copying Replayer(const Replayer& rhs); + /// Disallow assignment const Replayer& operator=(const Replayer& rhs); librbd::RBD* m_rbd; @@ -148,9 +152,9 @@ private: std::map m_images; boost::shared_mutex m_images_mutex; - // Actions are hashed across the trackers by ID. - // Number of trackers should probably be larger than the number of cores and prime. - // Should definitely be odd. + /// Actions are hashed across the trackers by ID. + /// Number of trackers should probably be larger than the number of cores and prime. + /// Should definitely be odd. const int m_num_action_trackers; action_tracker_d* m_action_trackers; }; diff --git a/src/rbd_replay/Ser.hpp b/src/rbd_replay/Ser.hpp index 2bada8f70bc2..130465dc4392 100644 --- a/src/rbd_replay/Ser.hpp +++ b/src/rbd_replay/Ser.hpp @@ -20,6 +20,11 @@ namespace rbd_replay { +/** + Helper for serializing data in an architecture-indepdendent way. + Everything is written big-endian. + @see Deser +*/ class Ser { public: Ser(std::ostream &out); diff --git a/src/rbd_replay/actions.hpp b/src/rbd_replay/actions.hpp index 5d3f4dc4cd45..068e4dc41394 100644 --- a/src/rbd_replay/actions.hpp +++ b/src/rbd_replay/actions.hpp @@ -20,19 +20,32 @@ #include "Deser.hpp" #include "rbd_loc.hpp" +// Stupid Doxygen requires this or else the typedef docs don't appear anywhere. +/// @file rbd_replay/actions.hpp + namespace rbd_replay { typedef uint64_t imagectx_id_t; typedef uint64_t thread_id_t; -// Even IDs are normal actions, odd IDs are completions +/// Even IDs are normal actions, odd IDs are completions. typedef uint32_t action_id_t; +/** + Dependencies link actions to earlier actions or completions. + If an action has a dependency \c d then it waits until \c d.time_delta nanoseconds after the action or completion with ID \c d.id has fired. +*/ struct dependency_d { + /// ID of the action or completion to wait for. action_id_t id; + /// Nanoseconds of delay to wait until after the action or completion fires. uint64_t time_delta; + /** + @param id ID of the action or completion to wait for. + @param time_delta Nanoseconds of delay to wait after the action or completion fires. + */ dependency_d(action_id_t id, uint64_t time_delta) : id(id), @@ -56,15 +69,32 @@ enum io_type { class PendingIO; +/** + %Context through which an Action interacts with its environment. + */ class ActionCtx { public: virtual ~ActionCtx() { } + /** + Returns the image with the given ID. + The image must have been previously tracked with put_image(imagectx_id_t,librbd::Image*). + */ virtual librbd::Image* get_image(imagectx_id_t imagectx_id) = 0; + /** + Tracks an image. + put_image(imagectx_id_t,librbd::Image*) must not have been called previously with the same ID, + and the image must not be NULL. + */ virtual void put_image(imagectx_id_t imagectx_id, librbd::Image* image) = 0; + /** + Stops tracking an Image and release it. + This deletes the C++ object, not the image itself. + The image must have been previously tracked with put_image(imagectx_id_t,librbd::Image*). + */ virtual void erase_image(imagectx_id_t imagectx_id) = 0; virtual librbd::RBD* rbd() = 0; @@ -81,10 +111,22 @@ public: virtual void stop() = 0; + /** + Maps an image name from the name in the original trace to the name that should be used when replaying. + @param image_name name of the image in the original trace + @param snap_name name of the snap in the orginal trace + @return image name to replay against + */ virtual rbd_loc map_image_name(std::string image_name, std::string snap_name) const = 0; }; +/** + Performs an %IO or a maintenance action such as starting or stopping a thread. + Actions are read from a replay file and scheduled by Replayer. + Corresponds to the IO class, except that Actions are executed by rbd-replay, + and IOs are used by rbd-replay-prep for processing the raw trace. + */ class Action { public: typedef boost::shared_ptr ptr; @@ -99,6 +141,7 @@ public: virtual void perform(ActionCtx &ctx) = 0; + /// Returns the ID of the completion corresponding to this action. action_id_t pending_io_id() { return m_id + 1; } @@ -120,6 +163,7 @@ public: return m_predecessors; } + /// Reads and constructs an action from the replay file. static ptr read_from(Deser &d); protected: @@ -137,9 +181,15 @@ private: const std::vector m_predecessors; }; +/// Writes human-readable debug information about the action to the stream. +/// @related Action std::ostream& operator<<(std::ostream& o, const Action& a); +/** + Placeholder for partially-constructed actions. + Does nothing, and does not appear in the replay file. + */ class DummyAction : public Action { public: DummyAction(action_id_t id, @@ -157,6 +207,7 @@ private: std::ostream& dump(std::ostream& o) const; }; + class StopThreadAction : public Action { public: explicit StopThreadAction(Action &src); diff --git a/src/rbd_replay/ios.hpp b/src/rbd_replay/ios.hpp index ad9ff2a5c992..5bebcd71731d 100644 --- a/src/rbd_replay/ios.hpp +++ b/src/rbd_replay/ios.hpp @@ -35,14 +35,40 @@ typedef std::set > io_set_t; typedef std::map > io_map_t; +/** + Calculates reachability of IOs in the dependency graph. + All IOs in \c deps which are not transitive dependencies of anything in \c base + is added to \c unreachable. + In other words, for every IO \c x in \c deps: if nothing in \c base depends on \c x, + and nothing in \c base has dependencies that depend on \c x, etc., + then \c x is added to \c unreachable. + Note that \c unreachable is \em not cleared, so the same set can be used across multiple + calls to collect dependencies. + @param[in] deps IOs to search for + @param[in] base root set of IOs to search from + @param[out] unreachable collects unreachable IOs + @related IO +*/ void batch_unreachable_from(const io_set_t& deps, const io_set_t& base, io_set_t* unreachable); + +/** + Used by rbd-replay-prep for processing the raw trace. + Corresponds to the Action class, except that Actions are executed by rbd-replay, + and IOs are used by rbd-replay-prep for processing the raw trace. + */ class IO : public boost::enable_shared_from_this { public: typedef boost::shared_ptr ptr; typedef boost::weak_ptr weak_ptr; + /** + @param ionum ID of this %IO + @param start_time time the %IO started, in nanoseconds + @param thread_id ID of the thread that issued the %IO + @param prev previously issued %IO on the same thread. NULL for the first %IO on a thread. + */ IO(action_id_t ionum, uint64_t start_time, thread_id_t thread_id, @@ -73,13 +99,14 @@ public: void add_dependencies(const io_set_t& deps); + /** + Returns the completion's number of successors, or 0 if the %IO does not have a completion. + */ uint64_t num_completion_successors() const { ptr c(m_completion.lock()); return c ? c->m_num_successors : 0; } - void write_to(Ser& out, io_type iotype) const; - virtual void write_to(Ser& out) const = 0; virtual bool is_completion() const { @@ -106,13 +133,20 @@ public: return m_num_successors; } - void write_debug_base(std::ostream& out, std::string iotype) const; - virtual void write_debug(std::ostream& out) const = 0; - // The result must be stored somewhere, or else m_completion will expire + /** + Creates the completion for this IO. + This may only be called once per IO, and may not be called on completion IOs. + The completion must be stored, or else m_completion will expire. + */ ptr create_completion(uint64_t start_time, thread_id_t thread_id); +protected: + void write_to(Ser& out, io_type iotype) const; + + void write_debug_base(std::ostream& out, std::string iotype) const; + private: action_id_t m_ionum; uint64_t m_start_time; @@ -123,6 +157,8 @@ private: ptr m_prev; }; +/// Used for dumping debug info. +/// @related IO std::ostream& operator<<(std::ostream& out, IO::ptr io); @@ -327,6 +363,7 @@ public: } }; +/// @related IO bool compare_io_ptrs_by_start_time(IO::ptr p1, IO::ptr p2); } diff --git a/src/rbd_replay/rbd_loc.hpp b/src/rbd_replay/rbd_loc.hpp index fab159ae7157..9865962fd3ef 100644 --- a/src/rbd_replay/rbd_loc.hpp +++ b/src/rbd_replay/rbd_loc.hpp @@ -19,19 +19,63 @@ namespace rbd_replay { +/** + Stores a pool, image name, and snap name triple. + rbd_locs can be converted to/from strings with the format pool/image\@snap. + The slash and at signs can be omitted if the pool and snap are empty, respectively. + Backslashes can be used to escape slashes and at signs in names. + Examples: + + |Pool | Image | Snap | String | + |------|-------|------|--------------------| + |rbd | vm | 1 | rbd/vm\@1 | + |rbd | vm | | rbd/vm | + | | vm | 1 | vm\@1 | + | | vm | | vm | + |rbd | | 1 | rbd/\@1 | + |rbd\@x| vm/y | 1 | rbd\\\@x/vm\\/y\@1 | + + (The empty string should obviously be avoided as the image name.) + + Note that the non-canonical forms /vm\@1 and rbd/vm\@ can also be parsed, + although they will be formatted as vm\@1 and rbd/vm. + */ struct rbd_loc { + /** + Constructs an rbd_loc with the empty string for the pool, image, and snap. + */ rbd_loc(); + /** + Constructs an rbd_loc with the given pool, image, and snap. + */ rbd_loc(std::string pool, std::string image, std::string snap); + /** + Parses an rbd_loc from the given string. + If parsing fails, the contents are unmodified. + @retval true if parsing succeeded + */ bool parse(std::string name_string); + /** + Returns the string representation of the locator. + */ std::string str() const; + /** + Compares the locators lexicographically by pool, then image, then snap. + */ int compare(const rbd_loc& rhs) const; + /** + Returns true if the locators have identical pool, image, and snap. + */ bool operator==(const rbd_loc& rhs) const; + /** + Compares the locators lexicographically by pool, then image, then snap. + */ bool operator<(const rbd_loc& rhs) const; std::string pool;