]> git.proxmox.com Git - ceph.git/blame - ceph/src/include/Context.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / include / Context.h
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15
16#ifndef CEPH_CONTEXT_H
17#define CEPH_CONTEXT_H
18
19#include "common/dout.h"
20
21#include <boost/function.hpp>
22#include <list>
23#include <set>
24#include <memory>
25
11fdf7f2
TL
26#include "include/ceph_assert.h"
27#include "common/Mutex.h"
7c673cae
FG
28
29#define mydout(cct, v) lgeneric_subdout(cct, context, v)
30
31/*
32 * GenContext - abstract callback class
33 */
34template <typename T>
35class GenContext {
36 GenContext(const GenContext& other);
37 const GenContext& operator=(const GenContext& other);
38
39 protected:
40 virtual void finish(T t) = 0;
41
42 public:
43 GenContext() {}
44 virtual ~GenContext() {} // we want a virtual destructor!!!
45
46 template <typename C>
47 void complete(C &&t) {
48 finish(std::forward<C>(t));
49 delete this;
50 }
51};
52
53template <typename T>
54using GenContextURef = std::unique_ptr<GenContext<T> >;
55
56/*
57 * Context - abstract callback class
58 */
11fdf7f2 59class Finisher;
7c673cae
FG
60class Context {
61 Context(const Context& other);
62 const Context& operator=(const Context& other);
63
64 protected:
65 virtual void finish(int r) = 0;
66
11fdf7f2
TL
67 // variant of finish that is safe to call "synchronously." override should
68 // return true.
69 virtual bool sync_finish(int r) {
70 return false;
71 }
72
7c673cae
FG
73 public:
74 Context() {}
75 virtual ~Context() {} // we want a virtual destructor!!!
76 virtual void complete(int r) {
77 finish(r);
78 delete this;
79 }
11fdf7f2
TL
80 virtual bool sync_complete(int r) {
81 if (sync_finish(r)) {
82 delete this;
83 return true;
84 }
85 return false;
86 }
7c673cae
FG
87};
88
89/**
90 * Simple context holding a single object
91 */
92template<class T>
93class ContainerContext : public Context {
94 T obj;
95public:
96 ContainerContext(T &obj) : obj(obj) {}
97 void finish(int r) override {}
98};
99template <typename T>
100ContainerContext<T> *make_container_context(T &&t) {
101 return new ContainerContext<T>(std::forward<T>(t));
102}
103
104template <class T>
105struct Wrapper : public Context {
106 Context *to_run;
107 T val;
108 Wrapper(Context *to_run, T val) : to_run(to_run), val(val) {}
109 void finish(int r) override {
110 if (to_run)
111 to_run->complete(r);
112 }
113};
114struct RunOnDelete {
115 Context *to_run;
116 RunOnDelete(Context *to_run) : to_run(to_run) {}
117 ~RunOnDelete() {
118 if (to_run)
119 to_run->complete(0);
120 }
121};
11fdf7f2 122typedef std::shared_ptr<RunOnDelete> RunOnDeleteRef;
7c673cae
FG
123
124template <typename T>
125struct LambdaContext : public Context {
126 T t;
127 LambdaContext(T &&t) : t(std::forward<T>(t)) {}
128 void finish(int) override {
129 t();
130 }
131};
132template <typename T>
133LambdaContext<T> *make_lambda_context(T &&t) {
134 return new LambdaContext<T>(std::move(t));
135}
136
137template <typename F, typename T>
138struct LambdaGenContext : GenContext<T> {
139 F f;
140 LambdaGenContext(F &&f) : f(std::forward<F>(f)) {}
141 void finish(T t) override {
142 f(std::forward<T>(t));
143 }
144};
145template <typename T, typename F>
146GenContextURef<T> make_gen_lambda_context(F &&f) {
147 return GenContextURef<T>(new LambdaGenContext<F, T>(std::move(f)));
148}
149
150/*
151 * finish and destroy a list of Contexts
152 */
11fdf7f2
TL
153template<class C>
154inline void finish_contexts(CephContext *cct, C& finished, int result = 0)
7c673cae
FG
155{
156 if (finished.empty())
157 return;
158
11fdf7f2 159 C ls;
7c673cae
FG
160 ls.swap(finished); // swap out of place to avoid weird loops
161
162 if (cct)
163 mydout(cct,10) << ls.size() << " contexts to finish with " << result << dendl;
11fdf7f2 164 for (Context* c : ls) {
7c673cae
FG
165 if (cct)
166 mydout(cct,10) << "---- " << c << dendl;
167 c->complete(result);
168 }
169}
170
171class C_NoopContext : public Context {
172public:
173 void finish(int r) override { }
174};
175
176
177struct C_Lock : public Context {
178 Mutex *lock;
179 Context *fin;
180 C_Lock(Mutex *l, Context *c) : lock(l), fin(c) {}
181 ~C_Lock() override {
182 delete fin;
183 }
184 void finish(int r) override {
185 if (fin) {
186 lock->Lock();
187 fin->complete(r);
188 fin = NULL;
189 lock->Unlock();
190 }
191 }
192};
193
194/*
195 * C_Contexts - set of Contexts
196 *
197 * ContextType must be an ancestor class of ContextInstanceType, or the same class.
198 * ContextInstanceType must be default-constructable.
199 */
11fdf7f2 200template <class ContextType, class ContextInstanceType, class Container = std::list<ContextType *>>
7c673cae
FG
201class C_ContextsBase : public ContextInstanceType {
202public:
203 CephContext *cct;
11fdf7f2 204 Container contexts;
7c673cae
FG
205
206 C_ContextsBase(CephContext *cct_)
207 : cct(cct_)
208 {
209 }
224ce89b
WB
210 ~C_ContextsBase() override {
211 for (auto c : contexts) {
212 delete c;
213 }
214 }
7c673cae
FG
215 void add(ContextType* c) {
216 contexts.push_back(c);
217 }
11fdf7f2
TL
218 void take(Container& ls) {
219 Container c;
220 c.swap(ls);
221 if constexpr (std::is_same_v<Container, std::list<ContextType *>>) {
222 contexts.splice(contexts.end(), c);
223 } else {
224 contexts.insert(contexts.end(), c.begin(), c.end());
225 }
7c673cae
FG
226 }
227 void complete(int r) override {
228 // Neuter any ContextInstanceType custom complete(), because although
229 // I want to look like it, I don't actually want to run its code.
230 Context::complete(r);
231 }
232 void finish(int r) override {
233 finish_contexts(cct, contexts, r);
234 }
235 bool empty() { return contexts.empty(); }
236
11fdf7f2
TL
237 template<class C>
238 static ContextType *list_to_context(C& cs) {
7c673cae
FG
239 if (cs.size() == 0) {
240 return 0;
241 } else if (cs.size() == 1) {
242 ContextType *c = cs.front();
243 cs.clear();
244 return c;
245 } else {
246 C_ContextsBase<ContextType, ContextInstanceType> *c(new C_ContextsBase<ContextType, ContextInstanceType>(0));
247 c->take(cs);
248 return c;
249 }
250 }
251};
252
253typedef C_ContextsBase<Context, Context> C_Contexts;
254
255/*
256 * C_Gather
257 *
258 * ContextType must be an ancestor class of ContextInstanceType, or the same class.
259 * ContextInstanceType must be default-constructable.
260 *
261 * BUG:? only reports error from last sub to have an error return
262 */
263template <class ContextType, class ContextInstanceType>
11fdf7f2 264class C_GatherBase {
7c673cae
FG
265private:
266 CephContext *cct;
267 int result;
268 ContextType *onfinish;
269#ifdef DEBUG_GATHER
270 std::set<ContextType*> waitfor;
271#endif
272 int sub_created_count;
273 int sub_existing_count;
274 mutable Mutex lock;
275 bool activated;
276
277 void sub_finish(ContextType* sub, int r) {
278 lock.Lock();
279#ifdef DEBUG_GATHER
11fdf7f2 280 ceph_assert(waitfor.count(sub));
7c673cae
FG
281 waitfor.erase(sub);
282#endif
283 --sub_existing_count;
284 mydout(cct,10) << "C_GatherBase " << this << ".sub_finish(r=" << r << ") " << sub
285#ifdef DEBUG_GATHER
286 << " (remaining " << waitfor << ")"
287#endif
288 << dendl;
289 if (r < 0 && result == 0)
290 result = r;
291 if ((activated == false) || (sub_existing_count != 0)) {
292 lock.Unlock();
293 return;
294 }
295 lock.Unlock();
296 delete_me();
297 }
298
299 void delete_me() {
300 if (onfinish) {
301 onfinish->complete(result);
302 onfinish = 0;
303 }
304 delete this;
305 }
306
307 class C_GatherSub : public ContextInstanceType {
308 C_GatherBase *gather;
309 public:
310 C_GatherSub(C_GatherBase *g) : gather(g) {}
311 void complete(int r) override {
312 // Cancel any customized complete() functionality
313 // from the Context subclass we're templated for,
314 // we only want to hit that in onfinish, not at each
315 // sub finish. e.g. MDSInternalContext.
316 Context::complete(r);
317 }
318 void finish(int r) override {
319 gather->sub_finish(this, r);
320 gather = 0;
321 }
322 ~C_GatherSub() override {
323 if (gather)
324 gather->sub_finish(this, 0);
325 }
326 };
327
328public:
329 C_GatherBase(CephContext *cct_, ContextType *onfinish_)
330 : cct(cct_), result(0), onfinish(onfinish_),
331 sub_created_count(0), sub_existing_count(0),
332 lock("C_GatherBase::lock", true, false), //disable lockdep
333 activated(false)
334 {
335 mydout(cct,10) << "C_GatherBase " << this << ".new" << dendl;
336 }
11fdf7f2 337 ~C_GatherBase() {
7c673cae
FG
338 mydout(cct,10) << "C_GatherBase " << this << ".delete" << dendl;
339 }
340 void set_finisher(ContextType *onfinish_) {
341 Mutex::Locker l(lock);
11fdf7f2 342 ceph_assert(!onfinish);
7c673cae
FG
343 onfinish = onfinish_;
344 }
345 void activate() {
346 lock.Lock();
11fdf7f2 347 ceph_assert(activated == false);
7c673cae
FG
348 activated = true;
349 if (sub_existing_count != 0) {
350 lock.Unlock();
351 return;
352 }
353 lock.Unlock();
354 delete_me();
355 }
356 ContextType *new_sub() {
357 Mutex::Locker l(lock);
11fdf7f2 358 ceph_assert(activated == false);
7c673cae
FG
359 sub_created_count++;
360 sub_existing_count++;
361 ContextType *s = new C_GatherSub(this);
362#ifdef DEBUG_GATHER
363 waitfor.insert(s);
364#endif
365 mydout(cct,10) << "C_GatherBase " << this << ".new_sub is " << sub_created_count << " " << s << dendl;
366 return s;
367 }
7c673cae
FG
368
369 inline int get_sub_existing_count() const {
370 Mutex::Locker l(lock);
371 return sub_existing_count;
372 }
373
374 inline int get_sub_created_count() const {
375 Mutex::Locker l(lock);
376 return sub_created_count;
377 }
378};
379
380/*
381 * The C_GatherBuilder remembers each C_Context created by
382 * C_GatherBuilder.new_sub() in a C_Gather. When a C_Context created
383 * by new_sub() is complete(), C_Gather forgets about it. When
384 * C_GatherBuilder notices that there are no C_Context left in
385 * C_Gather, it calls complete() on the C_Context provided as the
386 * second argument of the constructor (finisher).
387 *
388 * How to use C_GatherBuilder:
389 *
390 * 1. Create a C_GatherBuilder on the stack
391 * 2. Call gather_bld.new_sub() as many times as you want to create new subs
392 * It is safe to call this 0 times, or 100, or anything in between.
393 * 3. If you didn't supply a finisher in the C_GatherBuilder constructor,
394 * set one with gather_bld.set_finisher(my_finisher)
395 * 4. Call gather_bld.activate()
396 *
397 * Example:
398 *
399 * C_SaferCond all_done;
400 * C_GatherBuilder gb(g_ceph_context, all_done);
401 * j.submit_entry(1, first, 0, gb.new_sub()); // add a C_Context to C_Gather
402 * j.submit_entry(2, first, 0, gb.new_sub()); // add a C_Context to C_Gather
403 * gb.activate(); // consume C_Context as soon as they complete()
404 * all_done.wait(); // all_done is complete() after all new_sub() are complete()
405 *
406 * The finisher may be called at any point after step 4, including immediately
407 * from the activate() function.
408 * The finisher will never be called before activate().
409 *
410 * Note: Currently, subs must be manually freed by the caller (for some reason.)
411 */
412template <class ContextType, class GatherType>
413class C_GatherBuilderBase
414{
415public:
416 C_GatherBuilderBase(CephContext *cct_)
417 : cct(cct_), c_gather(NULL), finisher(NULL), activated(false)
418 {
419 }
420 C_GatherBuilderBase(CephContext *cct_, ContextType *finisher_)
421 : cct(cct_), c_gather(NULL), finisher(finisher_), activated(false)
422 {
423 }
424 ~C_GatherBuilderBase() {
425 if (c_gather) {
11fdf7f2 426 ceph_assert(activated); // Don't forget to activate your C_Gather!
7c673cae
FG
427 }
428 else {
429 delete finisher;
430 }
431 }
432 ContextType *new_sub() {
433 if (!c_gather) {
434 c_gather = new GatherType(cct, finisher);
435 }
436 return c_gather->new_sub();
437 }
438 void activate() {
439 if (!c_gather)
440 return;
11fdf7f2 441 ceph_assert(finisher != NULL);
7c673cae
FG
442 activated = true;
443 c_gather->activate();
444 }
445 void set_finisher(ContextType *finisher_) {
446 finisher = finisher_;
447 if (c_gather)
448 c_gather->set_finisher(finisher);
449 }
450 GatherType *get() const {
451 return c_gather;
452 }
453 bool has_subs() const {
454 return (c_gather != NULL);
455 }
456 int num_subs_created() {
11fdf7f2 457 ceph_assert(!activated);
7c673cae
FG
458 if (c_gather == NULL)
459 return 0;
460 return c_gather->get_sub_created_count();
461 }
462 int num_subs_remaining() {
11fdf7f2 463 ceph_assert(!activated);
7c673cae
FG
464 if (c_gather == NULL)
465 return 0;
466 return c_gather->get_sub_existing_count();
467 }
468
469private:
470 CephContext *cct;
471 GatherType *c_gather;
472 ContextType *finisher;
473 bool activated;
474};
475
476typedef C_GatherBase<Context, Context> C_Gather;
477typedef C_GatherBuilderBase<Context, C_Gather > C_GatherBuilder;
478
479class FunctionContext : public Context {
480public:
481 FunctionContext(boost::function<void(int)> &&callback)
482 : m_callback(std::move(callback))
483 {
484 }
485
486 void finish(int r) override {
487 m_callback(r);
488 }
489private:
490 boost::function<void(int)> m_callback;
491};
492
11fdf7f2
TL
493template <class ContextType>
494class ContextFactory {
495public:
496 virtual ~ContextFactory() {}
497 virtual ContextType *build() = 0;
498};
499
7c673cae
FG
500#undef mydout
501
502#endif