]> git.proxmox.com Git - ceph.git/blob - ceph/src/mon/PaxosService.h
ca75915841e591702b41a3d80444f52c78a99fa7
[ceph.git] / ceph / src / mon / PaxosService.h
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 #ifndef CEPH_PAXOSSERVICE_H
16 #define CEPH_PAXOSSERVICE_H
17
18 #include "include/Context.h"
19 #include "Paxos.h"
20 #include "Monitor.h"
21 #include "MonitorDBStore.h"
22
23 class Monitor;
24 class Paxos;
25
26 /**
27 * A Paxos Service is an abstraction that easily allows one to obtain an
28 * association between a Monitor and a Paxos class, in order to implement any
29 * service.
30 */
31 class PaxosService {
32 /**
33 * @defgroup PaxosService_h_class Paxos Service
34 * @{
35 */
36 public:
37 /**
38 * The Monitor to which this class is associated with
39 */
40 Monitor *mon;
41 /**
42 * The Paxos instance to which this class is associated with
43 */
44 Paxos *paxos;
45 /**
46 * Our name. This will be associated with the class implementing us, and will
47 * be used mainly for store-related operations.
48 */
49 string service_name;
50 /**
51 * If we are or have queued anything for proposal, this variable will be true
52 * until our proposal has been finished.
53 */
54 bool proposing;
55
56 bool need_immediate_propose = false;
57
58 protected:
59 /**
60 * Services implementing us used to depend on the Paxos version, back when
61 * each service would have a Paxos instance for itself. However, now we only
62 * have a single Paxos instance, shared by all the services. Each service now
63 * must keep its own version, if so they wish. This variable should be used
64 * for that purpose.
65 */
66 version_t service_version;
67
68 private:
69 /**
70 * Event callback responsible for proposing our pending value once a timer
71 * runs out and fires.
72 */
73 Context *proposal_timer;
74 /**
75 * If the implementation class has anything pending to be proposed to Paxos,
76 * then have_pending should be true; otherwise, false.
77 */
78 bool have_pending;
79
80 protected:
81
82 /**
83 * format of our state in leveldb, 0 for default
84 */
85 version_t format_version;
86
87
88
89 /**
90 * @defgroup PaxosService_h_callbacks Callback classes
91 * @{
92 */
93 /**
94 * Retry dispatching a given service message
95 *
96 * This callback class is used when we had to wait for some condition to
97 * become true while we were dispatching it.
98 *
99 * For instance, if the message's version isn't readable, according to Paxos,
100 * then we must wait for it to become readable. So, we just queue an
101 * instance of this class onto the Paxos::wait_for_readable function, and
102 * we will retry the whole dispatch again once the callback is fired.
103 */
104 class C_RetryMessage : public C_MonOp {
105 PaxosService *svc;
106 public:
107 C_RetryMessage(PaxosService *s, MonOpRequestRef op_) :
108 C_MonOp(op_), svc(s) { }
109 void _finish(int r) override {
110 if (r == -EAGAIN || r >= 0)
111 svc->dispatch(op);
112 else if (r == -ECANCELED)
113 return;
114 else
115 assert(0 == "bad C_RetryMessage return value");
116 }
117 };
118
119 /**
120 * @}
121 */
122
123 public:
124 /**
125 * @param mn A Monitor instance
126 * @param p A Paxos instance
127 * @param name Our service's name.
128 */
129 PaxosService(Monitor *mn, Paxos *p, string name)
130 : mon(mn), paxos(p), service_name(name),
131 proposing(false),
132 service_version(0), proposal_timer(0), have_pending(false),
133 format_version(0),
134 last_committed_name("last_committed"),
135 first_committed_name("first_committed"),
136 full_prefix_name("full"), full_latest_name("latest"),
137 cached_first_committed(0), cached_last_committed(0)
138 {
139 }
140
141 virtual ~PaxosService() {}
142
143 /**
144 * Get the service's name.
145 *
146 * @returns The service's name.
147 */
148 string get_service_name() { return service_name; }
149
150 /**
151 * Get the store prefixes we utilize
152 */
153 virtual void get_store_prefixes(set<string>& s) {
154 s.insert(service_name);
155 }
156
157 // i implement and you ignore
158 /**
159 * Informs this instance that it should consider itself restarted.
160 *
161 * This means that we will cancel our proposal_timer event, if any exists.
162 */
163 void restart();
164 /**
165 * Informs this instance that an election has finished.
166 *
167 * This means that we will invoke a PaxosService::discard_pending while
168 * setting have_pending to false (basically, ignore our pending state) and
169 * we will then make sure we obtain a new state.
170 *
171 * Our state shall be updated by PaxosService::_active if the Paxos is
172 * active; otherwise, we will wait for it to become active by adding a
173 * PaxosService::C_Active callback to it.
174 */
175 void election_finished();
176 /**
177 * Informs this instance that it is supposed to shutdown.
178 *
179 * Basically, it will instruct Paxos to cancel all events/callbacks and then
180 * will cancel the proposal_timer event if any exists.
181 */
182 void shutdown();
183
184 private:
185 /**
186 * Update our state by updating it from Paxos, and then creating a new
187 * pending state if need be.
188 *
189 * @remarks We only create a pending state we our Monitor is the Leader.
190 *
191 * @pre Paxos is active
192 * @post have_pending is true if our Monitor is the Leader and Paxos is
193 * active
194 */
195 void _active();
196
197 public:
198 /**
199 * Propose a new value through Paxos.
200 *
201 * This function should be called by the classes implementing
202 * PaxosService, in order to propose a new value through Paxos.
203 *
204 * @pre The implementation class implements the encode_pending function.
205 * @pre have_pending is true
206 * @pre Our monitor is the Leader
207 * @pre Paxos is active
208 * @post Cancel the proposal timer, if any
209 * @post have_pending is false
210 * @post propose pending value through Paxos
211 *
212 * @note This function depends on the implementation of encode_pending on
213 * the class that is implementing PaxosService
214 */
215 void propose_pending();
216
217 /**
218 * Let others request us to propose.
219 *
220 * At the moment, this is just a wrapper to propose_pending() with an
221 * extra check for is_writeable(), but it's a good practice to dissociate
222 * requests for proposals from direct usage of propose_pending() for
223 * future use -- we might want to perform additional checks or put a
224 * request on hold, for instance.
225 */
226 void request_proposal() {
227 assert(is_writeable());
228
229 propose_pending();
230 }
231 /**
232 * Request service @p other to perform a proposal.
233 *
234 * We could simply use the function above, requesting @p other directly,
235 * but we might eventually want to do something to the request -- say,
236 * set a flag stating we're waiting on a cross-proposal to be finished.
237 */
238 void request_proposal(PaxosService *other) {
239 assert(other != NULL);
240 assert(other->is_writeable());
241
242 other->request_proposal();
243 }
244
245 /**
246 * Dispatch a message by passing it to several different functions that are
247 * either implemented directly by this service, or that should be implemented
248 * by the class implementing this service.
249 *
250 * @param m A message
251 * @returns 'true' on successful dispatch; 'false' otherwise.
252 */
253 bool dispatch(MonOpRequestRef op);
254
255 void refresh(bool *need_bootstrap);
256 void post_refresh();
257
258 /**
259 * @defgroup PaxosService_h_override_funcs Functions that should be
260 * overridden.
261 *
262 * These functions should be overridden at will by the class implementing
263 * this service.
264 * @{
265 */
266 /**
267 * Create the initial state for your system.
268 *
269 * In some of ours the state is actually set up elsewhere so this does
270 * nothing.
271 */
272 virtual void create_initial() = 0;
273
274 /**
275 * Query the Paxos system for the latest state and apply it if it's newer
276 * than the current Monitor state.
277 */
278 virtual void update_from_paxos(bool *need_bootstrap) = 0;
279
280 /**
281 * Hook called after all services have refreshed their state from paxos
282 *
283 * This is useful for doing any update work that depends on other
284 * service's having up-to-date state.
285 */
286 virtual void post_paxos_update() {}
287
288 /**
289 * Init on startup
290 *
291 * This is called on mon startup, after all of the PaxosService instances'
292 * update_from_paxos() methods have been called
293 */
294 virtual void init() {}
295
296 /**
297 * Create the pending state.
298 *
299 * @invariant This function is only called on a Leader.
300 * @remarks This created state is then modified by incoming messages.
301 * @remarks Called at startup and after every Paxos ratification round.
302 */
303 virtual void create_pending() = 0;
304
305 /**
306 * Encode the pending state into a bufferlist for ratification and
307 * transmission as the next state.
308 *
309 * @invariant This function is only called on a Leader.
310 *
311 * @param t The transaction to hold all changes.
312 */
313 virtual void encode_pending(MonitorDBStore::TransactionRef t) = 0;
314
315 /**
316 * Discard the pending state
317 *
318 * @invariant This function is only called on a Leader.
319 *
320 * @remarks This function is NOT overridden in any of our code, but it is
321 * called in PaxosService::election_finished if have_pending is
322 * true.
323 */
324 virtual void discard_pending() { }
325
326 /**
327 * Look at the query; if the query can be handled without changing state,
328 * do so.
329 *
330 * @param m A query message
331 * @returns 'true' if the query was handled (e.g., was a read that got
332 * answered, was a state change that has no effect); 'false'
333 * otherwise.
334 */
335 virtual bool preprocess_query(MonOpRequestRef op) = 0;
336
337 /**
338 * Apply the message to the pending state.
339 *
340 * @invariant This function is only called on a Leader.
341 *
342 * @param m An update message
343 * @returns 'true' if the update message was handled (e.g., a command that
344 * went through); 'false' otherwise.
345 */
346 virtual bool prepare_update(MonOpRequestRef op) = 0;
347 /**
348 * @}
349 */
350
351 /**
352 * Determine if the Paxos system should vote on pending, and if so how long
353 * it should wait to vote.
354 *
355 * @param[out] delay The wait time, used so we can limit the update traffic
356 * spamming.
357 * @returns 'true' if the Paxos system should propose; 'false' otherwise.
358 */
359 virtual bool should_propose(double &delay);
360
361 /**
362 * force an immediate propose.
363 *
364 * This is meant to be called from prepare_update(op).
365 */
366 void force_immediate_propose() {
367 need_immediate_propose = true;
368 }
369
370 /**
371 * @defgroup PaxosService_h_courtesy Courtesy functions
372 *
373 * Courtesy functions, in case the class implementing this service has
374 * anything it wants/needs to do at these times.
375 * @{
376 */
377 /**
378 * This is called when the Paxos state goes to active.
379 *
380 * On the peon, this is after each election.
381 * On the leader, this is after each election, *and* after each completed
382 * proposal.
383 *
384 * @note This function may get called twice in certain recovery cases.
385 */
386 virtual void on_active() { }
387
388 /**
389 * This is called when we are shutting down
390 */
391 virtual void on_shutdown() {}
392
393 /**
394 * this is called when activating on the leader
395 *
396 * it should conditionally upgrade the on-disk format by proposing a transaction
397 */
398 virtual void upgrade_format() { }
399
400 /**
401 * this is called when we detect the store has just upgraded underneath us
402 */
403 virtual void on_upgrade() {}
404
405 /**
406 * Called when the Paxos system enters a Leader election.
407 *
408 * @remarks It's a courtesy method, in case the class implementing this
409 * service has anything it wants/needs to do at that time.
410 */
411 virtual void on_restart() { }
412 /**
413 * @}
414 */
415
416 /**
417 * Tick.
418 */
419 virtual void tick() {}
420
421 /**
422 * Get health information
423 *
424 * @param summary list of summary strings and associated severity
425 * @param detail optional list of detailed problem reports; may be NULL
426 */
427 virtual void get_health(list<pair<health_status_t,string> >& summary,
428 list<pair<health_status_t,string> > *detail,
429 CephContext *cct) const { }
430
431 private:
432 /**
433 * @defgroup PaxosService_h_store_keys Set of keys that are usually used on
434 * all the services implementing this
435 * class, and, being almost the only keys
436 * used, should be standardized to avoid
437 * mistakes.
438 * @{
439 */
440 const string last_committed_name;
441 const string first_committed_name;
442 const string full_prefix_name;
443 const string full_latest_name;
444 /**
445 * @}
446 */
447
448 /**
449 * @defgroup PaxosService_h_version_cache Variables holding cached values
450 * for the most used versions (first
451 * and last committed); we only have
452 * to read them when the store is
453 * updated, so in-between updates we
454 * may very well use cached versions
455 * and avoid the overhead.
456 * @{
457 */
458 version_t cached_first_committed;
459 version_t cached_last_committed;
460 /**
461 * @}
462 */
463
464 /**
465 * Callback list to be used whenever we are running a proposal through
466 * Paxos. These callbacks will be awaken whenever the said proposal
467 * finishes.
468 */
469 list<Context*> waiting_for_finished_proposal;
470
471 public:
472
473 /**
474 * Check if we are proposing a value through Paxos
475 *
476 * @returns true if we are proposing; false otherwise.
477 */
478 bool is_proposing() {
479 return proposing;
480 }
481
482 /**
483 * Check if we are in the Paxos ACTIVE state.
484 *
485 * @note This function is a wrapper for Paxos::is_active
486 *
487 * @returns true if in state ACTIVE; false otherwise.
488 */
489 bool is_active() {
490 return
491 !is_proposing() &&
492 (paxos->is_active() || paxos->is_updating() || paxos->is_writing());
493 }
494
495 /**
496 * Check if we are readable.
497 *
498 * This mirrors on the paxos check, except that we also verify that
499 *
500 * - the client hasn't seen the future relative to this PaxosService
501 * - this service isn't proposing.
502 * - we have committed our initial state (last_committed > 0)
503 *
504 * @param ver The version we want to check if is readable
505 * @returns true if it is readable; false otherwise
506 */
507 bool is_readable(version_t ver = 0) {
508 if (ver > get_last_committed() ||
509 !paxos->is_readable(0) ||
510 get_last_committed() == 0)
511 return false;
512 return true;
513 }
514
515 /**
516 * Check if we are writeable.
517 *
518 * We consider to be writeable iff:
519 *
520 * - we are not proposing a new version;
521 * - we are ready to be written to -- i.e., we have a pending value.
522 * - paxos is (active or updating or writing or refresh)
523 *
524 * @returns true if writeable; false otherwise
525 */
526 bool is_writeable() {
527 return is_write_ready();
528 }
529
530 /**
531 * Check if we are ready to be written to. This means we must have a
532 * pending value and be active.
533 *
534 * @returns true if we are ready to be written to; false otherwise.
535 */
536 bool is_write_ready() {
537 return is_active() && have_pending;
538 }
539
540 /**
541 * Wait for a proposal to finish.
542 *
543 * Add a callback to be awaken whenever our current proposal finishes being
544 * proposed through Paxos.
545 *
546 * @param c The callback to be awaken once the proposal is finished.
547 */
548 void wait_for_finished_proposal(MonOpRequestRef op, Context *c) {
549 if (op)
550 op->mark_event_string(service_name + ":wait_for_finished_proposal");
551 waiting_for_finished_proposal.push_back(c);
552 }
553 void wait_for_finished_proposal_ctx(Context *c) {
554 MonOpRequestRef o;
555 wait_for_finished_proposal(o, c);
556 }
557
558 /**
559 * Wait for us to become active
560 *
561 * @param c The callback to be awaken once we become active.
562 */
563 void wait_for_active(MonOpRequestRef op, Context *c) {
564 if (op)
565 op->mark_event_string(service_name + ":wait_for_active");
566
567 if (!is_proposing()) {
568 paxos->wait_for_active(op, c);
569 return;
570 }
571 wait_for_finished_proposal(op, c);
572 }
573 void wait_for_active_ctx(Context *c) {
574 MonOpRequestRef o;
575 wait_for_active(o, c);
576 }
577
578 /**
579 * Wait for us to become readable
580 *
581 * @param c The callback to be awaken once we become active.
582 * @param ver The version we want to wait on.
583 */
584 void wait_for_readable(MonOpRequestRef op, Context *c, version_t ver = 0) {
585 /* This is somewhat of a hack. We only do check if a version is readable on
586 * PaxosService::dispatch(), but, nonetheless, we must make sure that if that
587 * is why we are not readable, then we must wait on PaxosService and not on
588 * Paxos; otherwise, we may assert on Paxos::wait_for_readable() if it
589 * happens to be readable at that specific point in time.
590 */
591 if (op)
592 op->mark_event_string(service_name + ":wait_for_readable");
593
594 if (is_proposing() ||
595 ver > get_last_committed() ||
596 get_last_committed() == 0)
597 wait_for_finished_proposal(op, c);
598 else {
599 if (op)
600 op->mark_event_string(service_name + ":wait_for_readable/paxos");
601
602 paxos->wait_for_readable(op, c);
603 }
604 }
605
606 void wait_for_readable_ctx(Context *c, version_t ver = 0) {
607 MonOpRequestRef o; // will initialize the shared_ptr to NULL
608 wait_for_readable(o, c, ver);
609 }
610
611 /**
612 * Wait for us to become writeable
613 *
614 * @param c The callback to be awaken once we become writeable.
615 */
616 void wait_for_writeable(MonOpRequestRef op, Context *c) {
617 if (op)
618 op->mark_event_string(service_name + ":wait_for_writeable");
619
620 if (is_proposing())
621 wait_for_finished_proposal(op, c);
622 else if (!is_write_ready())
623 wait_for_active(op, c);
624 else
625 paxos->wait_for_writeable(op, c);
626 }
627 void wait_for_writeable_ctx(Context *c) {
628 MonOpRequestRef o;
629 wait_for_writeable(o, c);
630 }
631
632
633 /**
634 * @defgroup PaxosService_h_Trim Functions for trimming states
635 * @{
636 */
637 /**
638 * trim service states if appropriate
639 *
640 * Called at same interval as tick()
641 */
642 void maybe_trim();
643
644 /**
645 * Auxiliary function to trim our state from version @p from to version
646 * @p to, not including; i.e., the interval [from, to[
647 *
648 * @param t The transaction to which we will add the trim operations.
649 * @param from the lower limit of the interval to be trimmed
650 * @param to the upper limit of the interval to be trimmed (not including)
651 */
652 void trim(MonitorDBStore::TransactionRef t, version_t from, version_t to);
653
654 /**
655 * encode service-specific extra bits into trim transaction
656 *
657 * @param tx transaction
658 * @param first new first_committed value
659 */
660 virtual void encode_trim_extra(MonitorDBStore::TransactionRef tx,
661 version_t first) {}
662
663 /**
664 * Get the version we should trim to.
665 *
666 * Should be overloaded by service if it wants to trim states.
667 *
668 * @returns the version we should trim to; if we return zero, it should be
669 * assumed that there's no version to trim to.
670 */
671 virtual version_t get_trim_to() {
672 return 0;
673 }
674
675 /**
676 * @}
677 */
678 /**
679 * @defgroup PaxosService_h_Stash_Full
680 * @{
681 */
682 virtual bool should_stash_full();
683 /**
684 * Encode a full version on @p t
685 *
686 * @note We force every service to implement this function, since we strongly
687 * desire the encoding of full versions.
688 * @note Services that do not trim their state, will be bound to only create
689 * one full version. Full version stashing is determined/controled by
690 * trimming: we stash a version each time a trim is bound to erase the
691 * latest full version.
692 *
693 * @param t Transaction on which the full version shall be encoded.
694 */
695 virtual void encode_full(MonitorDBStore::TransactionRef t) = 0;
696
697 /**
698 * @}
699 */
700
701 /**
702 * Cancel events.
703 *
704 * @note This function is a wrapper for Paxos::cancel_events
705 */
706 void cancel_events() {
707 paxos->cancel_events();
708 }
709
710 /**
711 * @defgroup PaxosService_h_store_funcs Back storage interface functions
712 * @{
713 */
714 /**
715 * @defgroup PaxosService_h_store_modify Wrapper function interface to access
716 * the back store for modification
717 * purposes
718 * @{
719 */
720 void put_first_committed(MonitorDBStore::TransactionRef t, version_t ver) {
721 t->put(get_service_name(), first_committed_name, ver);
722 }
723 /**
724 * Set the last committed version to @p ver
725 *
726 * @param t A transaction to which we add this put operation
727 * @param ver The last committed version number being put
728 */
729 void put_last_committed(MonitorDBStore::TransactionRef t, version_t ver) {
730 t->put(get_service_name(), last_committed_name, ver);
731
732 /* We only need to do this once, and that is when we are about to make our
733 * first proposal. There are some services that rely on first_committed
734 * being set -- and it should! -- so we need to guarantee that it is,
735 * specially because the services itself do not do it themselves. They do
736 * rely on it, but they expect us to deal with it, and so we shall.
737 */
738 if (!get_first_committed())
739 put_first_committed(t, ver);
740 }
741 /**
742 * Put the contents of @p bl into version @p ver
743 *
744 * @param t A transaction to which we will add this put operation
745 * @param ver The version to which we will add the value
746 * @param bl A bufferlist containing the version's value
747 */
748 void put_version(MonitorDBStore::TransactionRef t, version_t ver,
749 bufferlist& bl) {
750 t->put(get_service_name(), ver, bl);
751 }
752 /**
753 * Put the contents of @p bl into a full version key for this service, that
754 * will be created with @p ver in mind.
755 *
756 * @param t The transaction to which we will add this put operation
757 * @param ver A version number
758 * @param bl A bufferlist containing the version's value
759 */
760 void put_version_full(MonitorDBStore::TransactionRef t,
761 version_t ver, bufferlist& bl) {
762 string key = mon->store->combine_strings(full_prefix_name, ver);
763 t->put(get_service_name(), key, bl);
764 }
765 /**
766 * Put the version number in @p ver into the key pointing to the latest full
767 * version of this service.
768 *
769 * @param t The transaction to which we will add this put operation
770 * @param ver A version number
771 */
772 void put_version_latest_full(MonitorDBStore::TransactionRef t, version_t ver) {
773 string key = mon->store->combine_strings(full_prefix_name, full_latest_name);
774 t->put(get_service_name(), key, ver);
775 }
776 /**
777 * Put the contents of @p bl into the key @p key.
778 *
779 * @param t A transaction to which we will add this put operation
780 * @param key The key to which we will add the value
781 * @param bl A bufferlist containing the value
782 */
783 void put_value(MonitorDBStore::TransactionRef t,
784 const string& key, bufferlist& bl) {
785 t->put(get_service_name(), key, bl);
786 }
787
788 /**
789 * Put integer value @v into the key @p key.
790 *
791 * @param t A transaction to which we will add this put operation
792 * @param key The key to which we will add the value
793 * @param v An integer
794 */
795 void put_value(MonitorDBStore::TransactionRef t,
796 const string& key, version_t v) {
797 t->put(get_service_name(), key, v);
798 }
799
800 /**
801 * @}
802 */
803
804 /**
805 * @defgroup PaxosService_h_store_get Wrapper function interface to access
806 * the back store for reading purposes
807 * @{
808 */
809
810 /**
811 * @defgroup PaxosService_h_version_cache Obtain cached versions for this
812 * service.
813 * @{
814 */
815 /**
816 * Get the first committed version
817 *
818 * @returns Our first committed version (that is available)
819 */
820 version_t get_first_committed() const{
821 return cached_first_committed;
822 }
823 /**
824 * Get the last committed version
825 *
826 * @returns Our last committed version
827 */
828 version_t get_last_committed() const{
829 return cached_last_committed;
830 }
831
832 /**
833 * @}
834 */
835
836 /**
837 * Get the contents of a given version @p ver
838 *
839 * @param ver The version being obtained
840 * @param bl The bufferlist to be populated
841 * @return 0 on success; <0 otherwise
842 */
843 virtual int get_version(version_t ver, bufferlist& bl) {
844 return mon->store->get(get_service_name(), ver, bl);
845 }
846 /**
847 * Get the contents of a given full version of this service.
848 *
849 * @param ver A version number
850 * @param bl The bufferlist to be populated
851 * @returns 0 on success; <0 otherwise
852 */
853 virtual int get_version_full(version_t ver, bufferlist& bl) {
854 string key = mon->store->combine_strings(full_prefix_name, ver);
855 return mon->store->get(get_service_name(), key, bl);
856 }
857 /**
858 * Get the latest full version number
859 *
860 * @returns A version number
861 */
862 version_t get_version_latest_full() {
863 string key = mon->store->combine_strings(full_prefix_name, full_latest_name);
864 return mon->store->get(get_service_name(), key);
865 }
866
867 /**
868 * Get a value from a given key.
869 *
870 * @param[in] key The key
871 * @param[out] bl The bufferlist to be populated with the value
872 */
873 int get_value(const string& key, bufferlist& bl) {
874 return mon->store->get(get_service_name(), key, bl);
875 }
876 /**
877 * Get an integer value from a given key.
878 *
879 * @param[in] key The key
880 */
881 version_t get_value(const string& key) {
882 return mon->store->get(get_service_name(), key);
883 }
884
885 /**
886 * @}
887 */
888 /**
889 * @}
890 */
891 };
892
893 #endif
894