]>
Commit | Line | Data |
---|---|---|
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 | #include "rgw_realm_reloader.h" | |
5 | #include "rgw_rados.h" | |
6 | ||
7 | #include "rgw_bucket.h" | |
8 | #include "rgw_log.h" | |
9 | #include "rgw_rest.h" | |
10 | #include "rgw_user.h" | |
11 | ||
224ce89b WB |
12 | #include "common/errno.h" |
13 | ||
7c673cae FG |
14 | #define dout_subsys ceph_subsys_rgw |
15 | ||
16 | #undef dout_prefix | |
17 | #define dout_prefix (*_dout << "rgw realm reloader: ") | |
18 | ||
19 | ||
20 | // safe callbacks from SafeTimer are unneccessary. reload() can take a long | |
21 | // time, so we don't want to hold the mutex and block handle_notify() for the | |
22 | // duration | |
23 | static constexpr bool USE_SAFE_TIMER_CALLBACKS = false; | |
24 | ||
25 | ||
224ce89b WB |
26 | RGWRealmReloader::RGWRealmReloader(RGWRados*& store, std::map<std::string, std::string>& service_map_meta, |
27 | Pauser* frontends) | |
7c673cae | 28 | : store(store), |
224ce89b | 29 | service_map_meta(service_map_meta), |
7c673cae FG |
30 | frontends(frontends), |
31 | timer(store->ctx(), mutex, USE_SAFE_TIMER_CALLBACKS), | |
32 | mutex("RGWRealmReloader"), | |
33 | reload_scheduled(nullptr) | |
34 | { | |
35 | timer.init(); | |
36 | } | |
37 | ||
38 | RGWRealmReloader::~RGWRealmReloader() | |
39 | { | |
40 | Mutex::Locker lock(mutex); | |
41 | timer.shutdown(); | |
42 | } | |
43 | ||
44 | class RGWRealmReloader::C_Reload : public Context { | |
45 | RGWRealmReloader* reloader; | |
46 | public: | |
47 | C_Reload(RGWRealmReloader* reloader) : reloader(reloader) {} | |
48 | void finish(int r) override { reloader->reload(); } | |
49 | }; | |
50 | ||
51 | void RGWRealmReloader::handle_notify(RGWRealmNotify type, | |
52 | bufferlist::iterator& p) | |
53 | { | |
54 | if (!store) { | |
55 | /* we're in the middle of reload */ | |
56 | return; | |
57 | } | |
58 | ||
59 | CephContext *const cct = store->ctx(); | |
60 | ||
61 | Mutex::Locker lock(mutex); | |
62 | if (reload_scheduled) { | |
63 | ldout(cct, 4) << "Notification on realm, reconfiguration " | |
64 | "already scheduled" << dendl; | |
65 | return; | |
66 | } | |
67 | ||
68 | reload_scheduled = new C_Reload(this); | |
69 | cond.SignalOne(); // wake reload() if it blocked on a bad configuration | |
70 | ||
71 | // schedule reload() without delay | |
72 | timer.add_event_after(0, reload_scheduled); | |
73 | ||
74 | ldout(cct, 4) << "Notification on realm, reconfiguration scheduled" << dendl; | |
75 | } | |
76 | ||
77 | void RGWRealmReloader::reload() | |
78 | { | |
79 | CephContext *const cct = store->ctx(); | |
80 | ldout(cct, 1) << "Pausing frontends for realm update..." << dendl; | |
81 | ||
82 | frontends->pause(); | |
83 | ||
84 | ldout(cct, 1) << "Frontends paused" << dendl; | |
85 | ||
86 | // TODO: make RGWRados responsible for rgw_log_usage lifetime | |
87 | rgw_log_usage_finalize(); | |
88 | ||
89 | // destroy the existing store | |
90 | RGWStoreManager::close_storage(store); | |
91 | store = nullptr; | |
92 | ||
93 | ldout(cct, 1) << "Store closed" << dendl; | |
94 | { | |
95 | // allow a new notify to reschedule us. it's important that we do this | |
96 | // before we start loading the new realm, or we could miss some updates | |
97 | Mutex::Locker lock(mutex); | |
98 | reload_scheduled = nullptr; | |
99 | } | |
100 | ||
101 | while (!store) { | |
102 | // recreate and initialize a new store | |
103 | store = RGWStoreManager::get_storage(cct, | |
104 | cct->_conf->rgw_enable_gc_threads, | |
105 | cct->_conf->rgw_enable_lc_threads, | |
106 | cct->_conf->rgw_enable_quota_threads, | |
31f18b77 | 107 | cct->_conf->rgw_run_sync_thread, |
28e407b8 AA |
108 | cct->_conf->rgw_dynamic_resharding, |
109 | cct->_conf->rgw_cache_enabled | |
110 | ); | |
7c673cae FG |
111 | |
112 | ldout(cct, 1) << "Creating new store" << dendl; | |
113 | ||
114 | RGWRados* store_cleanup = nullptr; | |
115 | { | |
116 | Mutex::Locker lock(mutex); | |
117 | ||
118 | // failure to recreate RGWRados is not a recoverable error, but we | |
119 | // don't want to assert or abort the entire cluster. instead, just | |
120 | // sleep until we get another notification, and retry until we get | |
121 | // a working configuration | |
122 | if (store == nullptr) { | |
123 | lderr(cct) << "Failed to reinitialize RGWRados after a realm " | |
124 | "configuration update. Waiting for a new update." << dendl; | |
125 | ||
126 | // sleep until another event is scheduled | |
127 | while (!reload_scheduled) | |
128 | cond.Wait(mutex); | |
129 | ||
130 | ldout(cct, 1) << "Woke up with a new configuration, retrying " | |
131 | "RGWRados initialization." << dendl; | |
132 | } | |
133 | ||
134 | if (reload_scheduled) { | |
135 | // cancel the event; we'll handle it now | |
136 | timer.cancel_event(reload_scheduled); | |
137 | reload_scheduled = nullptr; | |
138 | ||
139 | // if we successfully created a store, clean it up outside of the lock, | |
140 | // then continue to loop and recreate another | |
141 | std::swap(store, store_cleanup); | |
142 | } | |
143 | } | |
144 | ||
145 | if (store_cleanup) { | |
146 | ldout(cct, 4) << "Got another notification, restarting RGWRados " | |
147 | "initialization." << dendl; | |
148 | ||
149 | RGWStoreManager::close_storage(store_cleanup); | |
150 | } | |
151 | } | |
152 | ||
224ce89b WB |
153 | int r = store->register_to_service_map("rgw", service_map_meta); |
154 | if (r < 0) { | |
155 | lderr(cct) << "ERROR: failed to register to service map: " << cpp_strerror(-r) << dendl; | |
156 | ||
157 | /* ignore error */ | |
158 | } | |
159 | ||
7c673cae FG |
160 | ldout(cct, 1) << "Finishing initialization of new store" << dendl; |
161 | // finish initializing the new store | |
162 | ldout(cct, 1) << " - REST subsystem init" << dendl; | |
163 | rgw_rest_init(cct, store, store->get_zonegroup()); | |
164 | ldout(cct, 1) << " - user subsystem init" << dendl; | |
165 | rgw_user_init(store); | |
166 | ldout(cct, 1) << " - user subsystem init" << dendl; | |
167 | rgw_bucket_init(store->meta_mgr); | |
168 | ldout(cct, 1) << " - usage subsystem init" << dendl; | |
169 | rgw_log_usage_init(cct, store); | |
170 | ||
171 | ldout(cct, 1) << "Resuming frontends with new realm configuration." << dendl; | |
172 | ||
173 | frontends->resume(store); | |
174 | } |