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