summaryrefslogtreecommitdiffstats
path: root/src/common/Readahead.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/common/Readahead.h167
1 files changed, 167 insertions, 0 deletions
diff --git a/src/common/Readahead.h b/src/common/Readahead.h
new file mode 100644
index 000000000..716e58cd3
--- /dev/null
+++ b/src/common/Readahead.h
@@ -0,0 +1,167 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_READAHEAD_H
+#define CEPH_READAHEAD_H
+
+#include <list>
+#include <vector>
+
+#include "include/Context.h"
+#include "common/ceph_mutex.h"
+
+/**
+ This class provides common state and logic for code that needs to perform readahead
+ on linear things such as RBD images or files.
+ Unless otherwise specified, all methods are thread-safe.
+
+ Minimum and maximum readahead sizes may be violated by up to 50\% if alignment is enabled.
+ Minimum readahead size may be violated if the end of the readahead target is reached.
+ */
+class Readahead {
+public:
+ typedef std::pair<uint64_t, uint64_t> extent_t;
+
+ // equal to UINT64_MAX
+ static const uint64_t NO_LIMIT = 18446744073709551615ULL;
+
+ Readahead();
+
+ ~Readahead();
+
+ /**
+ Update state with new reads and return readahead to be performed.
+ If the length of the returned extent is 0, no readahead should be performed.
+ The readahead extent is guaranteed not to pass \c limit.
+
+ Note that passing in NO_LIMIT as the limit and truncating the returned extent
+ is not the same as passing in the correct limit, because the internal state
+ will differ in the two cases.
+
+ @param extents read operations since last call to update
+ @param limit size of the thing readahead is being applied to
+ */
+ extent_t update(const std::vector<extent_t>& extents, uint64_t limit);
+
+ /**
+ Update state with a new read and return readahead to be performed.
+ If the length of the returned extent is 0, no readahead should be performed.
+ The readahead extent is guaranteed not to pass \c limit.
+
+ Note that passing in NO_LIMIT as the limit and truncating the returned extent
+ is not the same as passing in the correct limit, because the internal state
+ will differ in the two cases.
+
+ @param offset offset of the read operation
+ @param length length of the read operation
+ @param limit size of the thing readahead is being applied to
+ */
+ extent_t update(uint64_t offset, uint64_t length, uint64_t limit);
+
+ /**
+ Increment the pending counter.
+ */
+ void inc_pending(int count = 1);
+
+ /**
+ Decrement the pending counter.
+ The counter must not be decremented below 0.
+ */
+ void dec_pending(int count = 1);
+
+ /**
+ Waits until the pending count reaches 0.
+ */
+ void wait_for_pending();
+ void wait_for_pending(Context *ctx);
+
+ /**
+ Sets the number of sequential requests necessary to trigger readahead.
+ */
+ void set_trigger_requests(int trigger_requests);
+
+ /**
+ Gets the minimum size of a readahead request, in bytes.
+ */
+ uint64_t get_min_readahead_size(void);
+
+ /**
+ Gets the maximum size of a readahead request, in bytes.
+ */
+ uint64_t get_max_readahead_size(void);
+
+ /**
+ Sets the minimum size of a readahead request, in bytes.
+ */
+ void set_min_readahead_size(uint64_t min_readahead_size);
+
+ /**
+ Sets the maximum size of a readahead request, in bytes.
+ */
+ void set_max_readahead_size(uint64_t max_readahead_size);
+
+ /**
+ Sets the alignment units.
+ If the end point of a readahead request can be aligned to an alignment unit
+ by increasing or decreasing the size of the request by 50\% or less, it will.
+ Alignments are tested in order, so larger numbers should almost always come first.
+ */
+ void set_alignments(const std::vector<uint64_t> &alignments);
+
+private:
+ /**
+ Records that a read request has been received.
+ m_lock must be held while calling.
+ */
+ void _observe_read(uint64_t offset, uint64_t length);
+
+ /**
+ Computes the next readahead request.
+ m_lock must be held while calling.
+ */
+ extent_t _compute_readahead(uint64_t limit);
+
+ /// Number of sequential requests necessary to trigger readahead
+ int m_trigger_requests;
+
+ /// Minimum size of a readahead request, in bytes
+ uint64_t m_readahead_min_bytes;
+
+ /// Maximum size of a readahead request, in bytes
+ uint64_t m_readahead_max_bytes;
+
+ /// Alignment units, in bytes
+ std::vector<uint64_t> m_alignments;
+
+ /// Held while reading/modifying any state except m_pending
+ ceph::mutex m_lock = ceph::make_mutex("Readahead::m_lock");
+
+ /// Number of consecutive read requests in the current sequential stream
+ int m_nr_consec_read;
+
+ /// Number of bytes read in the current sequenial stream
+ uint64_t m_consec_read_bytes;
+
+ /// Position of the read stream
+ uint64_t m_last_pos;
+
+ /// Position of the readahead stream
+ uint64_t m_readahead_pos;
+
+ /// When readahead is already triggered and the read stream crosses this point, readahead is continued
+ uint64_t m_readahead_trigger_pos;
+
+ /// Size of the next readahead request (barring changes due to alignment, etc.)
+ uint64_t m_readahead_size;
+
+ /// Number of pending readahead requests, as determined by inc_pending() and dec_pending()
+ int m_pending;
+
+ /// Lock for m_pending
+ ceph::mutex m_pending_lock = ceph::make_mutex("Readahead::m_pending_lock");
+
+ /// Waiters for pending readahead
+ std::list<Context *> m_pending_waiting;
+};
+
+#endif