Motr  M0
epoch.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2013-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 
30 #include "lib/misc.h"
31 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_OTHER
32 #include "lib/trace.h"
33 #include "lib/errno.h" /* ENOMEM */
34 #include "lib/memory.h"
35 #include "module/instance.h"
36 #include "motr/magic.h"
37 #include "rpc/rpc_machine.h"
38 #include "rpc/item.h"
39 #include "reqh/reqh.h"
40 
41 #include "ha/epoch.h"
42 
51 struct ha_client {
52  struct m0_confc *hc_confc;
53  struct m0_ref hc_ref;
54  struct m0_tlink hc_link;
55  uint64_t hc_magic;
56 };
57 
63 struct ha_global {
64  struct m0_tl hg_clients;
65  struct m0_mutex hg_guard;
66 };
67 
68 M0_TL_DESCR_DEFINE(hg_client, "ha global clients list", static,
69  struct ha_client, hc_link, hc_magic,
71 M0_TL_DEFINE(hg_client, static, struct ha_client);
72 
73 M0_TL_DESCR_DEFINE(ham, "ha epoch monitor", static,
74  struct m0_ha_epoch_monitor, hem_linkage, hem_magix,
76 M0_TL_DEFINE(ham, static, struct m0_ha_epoch_monitor);
77 M0_INTERNAL const uint64_t M0_HA_EPOCH_NONE = 0ULL;
78 
79 static int default_mon_future(struct m0_ha_epoch_monitor *self,
80  uint64_t epoch, const struct m0_rpc_item *item)
81 {
82  return M0_HEO_OBEY;
83 }
84 
85 M0_INTERNAL void m0_ha_domain_init(struct m0_ha_domain *dom, uint64_t epoch)
86 {
87  dom->hdo_epoch = epoch;
88  m0_rwlock_init(&dom->hdo_lock);
89  ham_tlist_init(&dom->hdo_monitors);
90  dom->hdo_default_mon = (struct m0_ha_epoch_monitor) {
91  .hem_future = default_mon_future
92  };
93  m0_ha_domain_monitor_add(dom, &dom->hdo_default_mon);
94 }
95 
96 M0_INTERNAL void m0_ha_domain_fini(struct m0_ha_domain *dom)
97 {
98  m0_ha_domain_monitor_del(dom, &dom->hdo_default_mon);
99  ham_tlist_fini(&dom->hdo_monitors);
100  m0_rwlock_fini(&dom->hdo_lock);
101 }
102 
103 M0_INTERNAL void m0_ha_domain_monitor_add(struct m0_ha_domain *dom,
104  struct m0_ha_epoch_monitor *mon)
105 {
106  m0_rwlock_write_lock(&dom->hdo_lock);
107  ham_tlink_init_at(mon, &dom->hdo_monitors);
108  m0_rwlock_write_unlock(&dom->hdo_lock);
109 }
110 
111 M0_INTERNAL void m0_ha_domain_monitor_del(struct m0_ha_domain *dom,
112  struct m0_ha_epoch_monitor *mon)
113 {
114  m0_rwlock_write_lock(&dom->hdo_lock);
115  ham_tlist_del(mon);
116  m0_rwlock_write_unlock(&dom->hdo_lock);
117 }
118 
119 M0_INTERNAL uint64_t m0_ha_domain_get_read(struct m0_ha_domain *dom)
120 {
121  m0_rwlock_read_lock(&dom->hdo_lock);
122  return dom->hdo_epoch;
123 }
124 
125 M0_INTERNAL void m0_ha_domain_put_read(struct m0_ha_domain *dom)
126 {
127  m0_rwlock_read_unlock(&dom->hdo_lock);
128 }
129 
130 M0_INTERNAL uint64_t m0_ha_domain_get_write(struct m0_ha_domain *dom)
131 {
132  m0_rwlock_write_lock(&dom->hdo_lock);
133  return dom->hdo_epoch;
134 }
135 
136 M0_INTERNAL void m0_ha_domain_put_write(struct m0_ha_domain *dom,
137  uint64_t epoch)
138 {
139  M0_PRE(epoch >= dom->hdo_epoch);
140  dom->hdo_epoch = epoch;
141  m0_rwlock_write_unlock(&dom->hdo_lock);
142 }
143 
144 M0_INTERNAL int m0_ha_global_init(void)
145 {
146  struct ha_global *hg;
147 
148  M0_ALLOC_PTR(hg);
149  if (hg == NULL)
150  return M0_ERR(-ENOMEM);
151  m0_get()->i_moddata[M0_MODULE_HA] = hg;
152  m0_mutex_init(&hg->hg_guard);
153  hg_client_tlist_init(&hg->hg_clients);
154  return M0_RC(0);
155 }
156 
157 M0_INTERNAL void m0_ha_global_fini(void)
158 {
159  struct ha_global *hg = m0_get()->i_moddata[M0_MODULE_HA];
160 
161  M0_PRE(hg != NULL);
162  hg_client_tlist_fini(&hg->hg_clients);
163  m0_mutex_fini(&hg->hg_guard);
164  m0_free0(&hg);
165 }
166 
167 static inline void ha_global_lock(struct ha_global *hg)
168 {
169  m0_mutex_lock(&hg->hg_guard);
170 }
171 
172 static inline void ha_global_unlock(struct ha_global *hg)
173 {
175 }
176 
182 static void ha_client_release(struct m0_ref *ref)
183 {
184  struct ha_client *client;
185 
186  client = container_of(ref, struct ha_client, hc_ref);
187  hg_client_tlink_del_fini(client);
188  m0_free(client);
189 }
190 
191 M0_INTERNAL int m0_ha_client_add(struct m0_confc *confc)
192 {
193  struct ha_global *hg = m0_get()->i_moddata[M0_MODULE_HA];
194  struct ha_client *client;
195  int rc;
196 
197  M0_ENTRY();
198  M0_PRE(hg != NULL);
199  /*
200  * Only properly initialised confc allowed to register here. Otherwise
201  * early HA notifications acceptance to cause a crash on locking cache
202  * in ha_state_accept()!
203  */
205 
206  ha_global_lock(hg);
207  client = m0_tl_find(hg_client, item, &hg->hg_clients,
208  item->hc_confc == confc);
209  if (client == NULL) {
211  if (client == NULL) {
212  rc = -ENOMEM;
213  goto err;
214  }
215  client->hc_confc = confc;
216  hg_client_tlink_init_at_tail(client, &hg->hg_clients);
217  m0_ref_init(&client->hc_ref, 1, ha_client_release);
218  } else {
219  m0_ref_get(&client->hc_ref);
220  rc = -EALREADY;
221  goto err;
222  }
223  ha_global_unlock(hg);
224  return M0_RC(0);
225 
226 err:
227  ha_global_unlock(hg);
228  return M0_ERR(rc);
229 
230 }
231 
232 M0_INTERNAL int m0_ha_client_del(struct m0_confc *confc)
233 {
234  struct ha_global *hg = m0_get()->i_moddata[M0_MODULE_HA];
235  struct ha_client *client;
236  int rc = 0;
237 
238  M0_ENTRY();
239  M0_PRE(hg != NULL);
240  ha_global_lock(hg);
241  client = m0_tl_find(hg_client, item, &hg->hg_clients,
242  item->hc_confc == confc);
243  if (client != NULL)
244  m0_ref_put(&client->hc_ref);
245  else
246  rc = -ENOENT;
247  ha_global_unlock(hg);
248  return M0_RC(rc);
249 }
250 
252  const void *data,
253  uint64_t data2)
254 {
255  struct ha_global *hg = m0_get()->i_moddata[M0_MODULE_HA];
256  struct ha_client *client;
257 
258  M0_PRE(hg != NULL);
259  ha_global_lock(hg);
260  m0_tl_for(hg_client, &hg->hg_clients, client) {
261  iter(client->hc_confc, data, data2);
262  } m0_tl_endfor;
263  ha_global_unlock(hg);
264 }
265 
266 M0_INTERNAL int m0_ha_epoch_check(const struct m0_rpc_item *item)
267 {
268  struct m0_ha_domain *ha_dom;
269  uint64_t item_epoch = item->ri_ha_epoch;
270  uint64_t epoch;
271  struct m0_ha_epoch_monitor *mon;
272  int rc = 0;
273 
274  ha_dom = &item->ri_rmachine->rm_reqh->rh_hadom;
275  M0_LOG(M0_DEBUG, "mine=%lu rcvd=%lu",
276  (unsigned long)ha_dom->hdo_epoch,
277  (unsigned long)item_epoch);
278  if (item_epoch == ha_dom->hdo_epoch)
279  return 0;
280 
281  epoch = m0_ha_domain_get_write(ha_dom);
282 
283  /*
284  * Domain epoch could be changed before we took the lock
285  * with m0_ha_domain_get_write(), so let's check it again.
286  */
287  if (epoch == item_epoch)
288  goto out;
289 
290  m0_tl_for(ham, &ha_dom->hdo_monitors, mon) {
291  if (item_epoch > epoch && mon->hem_future != NULL)
292  rc = mon->hem_future(mon, epoch, item);
293  else if (mon->hem_past != NULL)
294  rc = mon->hem_past(mon, epoch, item);
295  else
296  continue;
297 
298  if (rc == M0_HEO_CONTINUE) {
299  continue;
300  } else if (rc == M0_HEO_OK) {
301  break;
302  } else if (rc == M0_HEO_OBEY) {
303  M0_LOG(M0_DEBUG, "old=%lu new=%lu",
304  (unsigned long)epoch,
305  (unsigned long)item_epoch);
306  epoch = item_epoch;
307  break;
308  } else if (M0_IN(rc, (M0_HEO_DROP, M0_HEO_ERROR))) {
309  rc = 1;
310  break;
311  }
312  } m0_tl_endfor;
313 
314 out:
315  m0_ha_domain_put_write(ha_dom, epoch);
316 
317  return M0_RC(rc);
318 }
319 
320 #undef M0_TRACE_SUBSYSTEM
321 
325 /*
326  * Local variables:
327  * c-indentation-style: "K&R"
328  * c-basic-offset: 8
329  * tab-width: 8
330  * fill-column: 80
331  * scroll-step: 1
332  * End:
333  */
334 /*
335  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
336  */
#define M0_PRE(cond)
uint64_t hdo_epoch
Definition: epoch.h:113
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
M0_INTERNAL void m0_ha_global_fini(void)
Definition: epoch.c:157
struct m0_ref hc_ref
Definition: epoch.c:53
struct m0_ha_domain rh_hadom
Definition: reqh.h:156
#define NULL
Definition: misc.h:38
struct m0_confc * hc_confc
Definition: epoch.c:52
#define M0_LOG(level,...)
Definition: trace.h:167
M0_INTERNAL void m0_ha_domain_put_read(struct m0_ha_domain *dom)
Definition: epoch.c:125
M0_INTERNAL const uint64_t M0_HA_EPOCH_NONE
Definition: epoch.c:77
struct m0_mutex * ca_lock
Definition: cache.h:102
M0_INTERNAL int m0_ha_client_del(struct m0_confc *confc)
Definition: epoch.c:232
M0_INTERNAL void m0_rwlock_write_lock(struct m0_rwlock *lock)
Definition: rwlock.c:42
struct m0_bufvec data
Definition: di.c:40
M0_TL_DEFINE(hg_client, static, struct ha_client)
M0_INTERNAL struct m0 * m0_get(void)
Definition: instance.c:41
#define container_of(ptr, type, member)
Definition: misc.h:33
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
M0_INTERNAL void m0_ha_clients_iterate(m0_ha_client_cb_t iter, const void *data, uint64_t data2)
Definition: epoch.c:251
static struct m0_rpc_item * item
Definition: item.c:56
M0_INTERNAL void m0_rwlock_init(struct m0_rwlock *lock)
Definition: rwlock.c:32
#define m0_tl_endfor
Definition: tlist.h:700
M0_INTERNAL uint64_t m0_ha_domain_get_read(struct m0_ha_domain *dom)
Definition: epoch.c:119
return M0_RC(rc)
#define M0_ENTRY(...)
Definition: trace.h:170
M0_INTERNAL void m0_ha_domain_fini(struct m0_ha_domain *dom)
Definition: epoch.c:96
M0_INTERNAL void m0_ref_put(struct m0_ref *ref)
Definition: refs.c:38
M0_INTERNAL int m0_ha_global_init(void)
Definition: epoch.c:144
void m0_ref_init(struct m0_ref *ref, int init_num, void(*release)(struct m0_ref *ref))
Definition: refs.c:24
return M0_ERR(-EOPNOTSUPP)
M0_INTERNAL void m0_ref_get(struct m0_ref *ref)
Definition: refs.c:32
Definition: refs.h:34
#define m0_free0(pptr)
Definition: memory.h:77
void client(struct client_params *params)
Definition: main.c:233
static struct m0_confc * confc
Definition: file.c:94
struct m0_tl hg_clients
Definition: epoch.c:64
Definition: tlist.h:251
Definition: client.h:37
static struct m0_stob_domain * dom
Definition: storage.c:38
struct m0_conf_cache cc_cache
Definition: confc.h:394
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
M0_INTERNAL int m0_ha_epoch_check(const struct m0_rpc_item *item)
Definition: epoch.c:266
M0_INTERNAL void m0_ha_domain_put_write(struct m0_ha_domain *dom, uint64_t epoch)
Definition: epoch.c:136
struct m0_tlink hc_link
Definition: epoch.c:54
M0_INTERNAL void m0_ha_domain_init(struct m0_ha_domain *dom, uint64_t epoch)
Definition: epoch.c:85
M0_INTERNAL void m0_rwlock_write_unlock(struct m0_rwlock *lock)
Definition: rwlock.c:47
static void ha_global_lock(struct ha_global *hg)
Definition: epoch.c:167
uint64_t hc_magic
Definition: epoch.c:55
static int default_mon_future(struct m0_ha_epoch_monitor *self, uint64_t epoch, const struct m0_rpc_item *item)
Definition: epoch.c:79
int(* hem_past)(struct m0_ha_epoch_monitor *self, uint64_t epoch, const struct m0_rpc_item *item)
Definition: epoch.h:91
int(* hem_future)(struct m0_ha_epoch_monitor *self, uint64_t epoch, const struct m0_rpc_item *item)
Definition: epoch.h:97
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
void * i_moddata[M0_MODULE_NR]
Definition: instance.h:94
static void ha_global_unlock(struct ha_global *hg)
Definition: epoch.c:172
static void ha_client_release(struct m0_ref *ref)
Definition: epoch.c:182
struct m0_mutex hg_guard
Definition: epoch.c:65
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
M0_INTERNAL void m0_rwlock_read_lock(struct m0_rwlock *lock)
Definition: rwlock.c:52
M0_INTERNAL void m0_rwlock_fini(struct m0_rwlock *lock)
Definition: rwlock.c:37
M0_INTERNAL int m0_ha_client_add(struct m0_confc *confc)
Definition: epoch.c:191
M0_INTERNAL uint64_t m0_ha_domain_get_write(struct m0_ha_domain *dom)
Definition: epoch.c:130
M0_INTERNAL void m0_rwlock_read_unlock(struct m0_rwlock *lock)
Definition: rwlock.c:57
#define out(...)
Definition: gen.c:41
struct m0_rpc_machine * ri_rmachine
Definition: item.h:160
M0_INTERNAL void m0_ha_domain_monitor_del(struct m0_ha_domain *dom, struct m0_ha_epoch_monitor *mon)
Definition: epoch.c:111
#define m0_tl_find(name, var, head,...)
Definition: tlist.h:757
M0_INTERNAL void m0_ha_domain_monitor_add(struct m0_ha_domain *dom, struct m0_ha_epoch_monitor *mon)
Definition: epoch.c:103
#define m0_tl_for(name, head, obj)
Definition: tlist.h:695
void m0_free(void *data)
Definition: memory.c:146
Definition: mutex.h:47
void(* m0_ha_client_cb_t)(void *client, const void *data, uint64_t data2)
Definition: epoch.h:236
int32_t rc
Definition: trigger_fop.h:47
uint64_t ri_ha_epoch
Definition: item.h:136
struct m0_tl hdo_monitors
Definition: epoch.h:122
M0_TL_DESCR_DEFINE(hg_client, "ha global clients list", static, struct ha_client, hc_link, hc_magic, M0_HA_CLIENT_MAGIC, M0_HA_CLIENT_HEAD_MAGIC)
struct m0_reqh * rm_reqh
Definition: rpc_machine.h:105