+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include <errno.h>
#include "common/Throttle.h"
#include "common/dout.h"
}
return count.read();
}
+
+SimpleThrottle::SimpleThrottle(uint64_t max, bool ignore_enoent)
+ : m_lock("SimpleThrottle"),
+ m_max(max),
+ m_current(0),
+ m_ret(0),
+ m_ignore_enoent(ignore_enoent)
+{
+}
+
+SimpleThrottle::~SimpleThrottle()
+{
+ Mutex::Locker l(m_lock);
+ assert(m_current == 0);
+}
+
+void SimpleThrottle::start_op()
+{
+ Mutex::Locker l(m_lock);
+ while (m_max == m_current)
+ m_cond.Wait(m_lock);
+ ++m_current;
+}
+
+void SimpleThrottle::end_op(int r)
+{
+ Mutex::Locker l(m_lock);
+ --m_current;
+ if (r < 0 && !m_ret && (r != -ENOENT || m_ignore_enoent))
+ m_ret = r;
+ m_cond.Signal();
+}
+
+int SimpleThrottle::wait_for_ret()
+{
+ Mutex::Locker l(m_lock);
+ while (m_current > 0)
+ m_cond.Wait(m_lock);
+ return m_ret;
+}
};
+/**
+ * @class SimpleThrottle
+ * This is a simple way to bound the number of concurrent operations.
+ *
+ * It tracks the first error encountered, and makes it available
+ * when all requests are complete. wait_for_ret() should be called
+ * before the instance is destroyed.
+ *
+ * Re-using the same instance isn't safe if you want to check each set
+ * of operations for errors, since the return value is not reset.
+ */
+class SimpleThrottle {
+public:
+ SimpleThrottle(uint64_t max, bool ignore_enoent);
+ ~SimpleThrottle();
+ void start_op();
+ void end_op(int r);
+ int wait_for_ret();
+private:
+ Mutex m_lock;
+ Cond m_cond;
+ uint64_t m_max;
+ uint64_t m_current;
+ int m_ret;
+ bool m_ignore_enoent;
+};
+
+class C_SimpleThrottle : public Context {
+public:
+ C_SimpleThrottle(SimpleThrottle *throttle) : m_throttle(throttle) {}
+ virtual void finish(int r) {
+ m_throttle->end_op(r);
+ }
+private:
+ SimpleThrottle *m_throttle;
+};
+
#endif