Motr  M0
locality.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2012-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 #include "lib/misc.h" /* m0_forall */
24 #include "lib/mutex.h"
25 #include "lib/errno.h"
26 #include "lib/assert.h"
27 #include "lib/locality.h"
28 #include "lib/finject.h"
29 #include "fop/fom.h"
30 #include "fop/fom_simple.h"
31 #include "reqh/reqh.h"
32 #include "reqh/reqh_service.h"
33 #include "ut/ut.h"
34 
35 enum {
36  NR = 4096,
37  X_VALUE = 6
38 };
39 
40 static bool passed[NR];
41 static uint64_t core[NR];
42 static struct m0_mutex lock;
43 static struct m0_semaphore sem[NR];
44 static struct m0_sm_ast ast[NR];
45 static struct m0_reqh reqh;
46 static struct m0_fom_simple s[NR];
47 static struct m0_atomic64 hoarded;
48 static bool free_func_called;
49 
50 static void fom_simple_svc_start(void)
51 {
53  struct m0_reqh_service *service;
54  int rc;
55 
56  stype = m0_reqh_service_type_find("simple-fom-service");
57  M0_ASSERT(stype != NULL);
59  M0_ASSERT(rc == 0);
61  &M0_FID_INIT(0xdeadbeef, 0xbeefdead));
63  M0_ASSERT(rc == 0);
65 }
66 
68 {
69  int result;
70 
71  M0_SET0(&reqh);
72  result = M0_REQH_INIT(&reqh,
73  .rhia_dtm = (void*)1,
74  .rhia_db = NULL,
75  .rhia_mdstore = (void*)1,
76  .rhia_fid = &g_process_fid,
77  );
78  M0_UT_ASSERT(result == 0);
81  return &reqh;
82 }
83 
84 void m0_ut__reqh_fini(void)
85 {
89 }
90 
91 static void _cb0(struct m0_sm_group *grp, struct m0_sm_ast *a)
92 {
93  unsigned idx = a - ast;
96  passed[idx] = true;
99  m0_semaphore_up(&sem[idx]);
100 }
101 
102 static int expected;
103 static int simple_tick(struct m0_fom *fom, int *x, int *__unused)
104 {
105 
106  M0_UT_ASSERT(*x == expected);
107 
108  ++expected;
109  if (++*x < NR)
110  return M0_FSO_AGAIN;
111  else {
112  m0_semaphore_up(&sem[0]);
113  return -1;
114  }
115 }
116 
117 static int tick_once(struct m0_fom *fom, int *x, int *__unused)
118 {
119  return -1;
120 }
121 
122 void free_func(struct m0_fom_simple *sfom)
123 {
124  free_func_called = true;
125  m0_semaphore_up(&sem[0]);
126 }
127 
128 enum {
132 };
133 
135  [M0_FOM_PHASE_INIT] = {
136  .sd_name = "init",
137  .sd_allowed = M0_BITS(SEMISIMPLE_S0),
138  .sd_flags = M0_SDF_INITIAL
139  },
140  [SEMISIMPLE_S0] = {
141  .sd_name = "ss0",
142  .sd_allowed = M0_BITS(SEMISIMPLE_S1)
143  },
144  [SEMISIMPLE_S1] = {
145  .sd_name = "ss1",
146  .sd_allowed = M0_BITS(SEMISIMPLE_S1, SEMISIMPLE_S2)
147  },
148  [SEMISIMPLE_S2] = {
149  .sd_name = "ss2",
150  .sd_allowed = M0_BITS(M0_FOM_PHASE_FINISH)
151  },
152  [M0_FOM_PHASE_FINISH] = {
153  .sd_name = "done",
154  .sd_flags = M0_SDF_TERMINAL
155  }
156 };
157 
158 static struct m0_sm_conf semisimple_conf = {
159  .scf_name = "semisimple fom",
160  .scf_nr_states = ARRAY_SIZE(semisimple_phases),
161  .scf_state = semisimple_phases
162 };
163 
164 static int semisimple_tick(struct m0_fom *fom, int *x, int *phase)
165 {
166  switch (*phase) {
167  case M0_FOM_PHASE_INIT:
168  M0_UT_ASSERT(*x == NR);
169  *phase = SEMISIMPLE_S0;
170  return M0_FSO_AGAIN;
171  case SEMISIMPLE_S0:
172  M0_UT_ASSERT(*x == NR);
173  *phase = SEMISIMPLE_S1;
174  --*x;
175  m0_semaphore_up(&sem[0]);
176  return M0_FSO_WAIT;
177  case SEMISIMPLE_S1:
178  M0_UT_ASSERT(*x < NR);
179  *phase = --*x == 0 ? SEMISIMPLE_S2 : SEMISIMPLE_S1;
180  return M0_FSO_AGAIN;
181  case SEMISIMPLE_S2:
182  M0_UT_ASSERT(*x == 0);
183  m0_semaphore_up(&sem[0]);
184  return -1;
185  default:
186  M0_UT_ASSERT(0);
187  return -1;
188  }
189 }
190 
191 static int cat_tick(struct m0_fom *fom, void *null, int *__unused)
192 {
193  struct m0_fom_simple *whisker = container_of(fom, struct m0_fom_simple,
194  si_fom);
195  int idx = whisker->si_locality;
196  M0_UT_ASSERT(null == NULL);
198  M0_UT_ASSERT(whisker == &s[idx]);
200  m0_semaphore_up(&sem[idx]);
201  return -1;
202 }
203 
204 void test_locality(void)
205 {
206  unsigned i;
207  struct m0_bitmap online;
208  int result;
209  size_t here;
210  int nr;
211 
214  for (i = 0; i < ARRAY_SIZE(sem); ++i) {
215  m0_semaphore_init(&sem[i], 0);
216  ast[i].sa_cb = &_cb0;
217  }
218 
219  here = m0_locality_here()->lo_idx;
220  m0_sm_ast_post(m0_locality_get(here)->lo_grp, &ast[0]);
221  m0_semaphore_down(&sem[0]);
222  M0_UT_ASSERT(passed[0]);
223  passed[0] = false;
224  M0_UT_ASSERT(m0_forall(j, ARRAY_SIZE(core), core[j] == !!(j == here)));
225  core[here] = 0;
226 
227  for (i = 0; i < NR; ++i)
228  m0_sm_ast_post(m0_locality_get(i)->lo_grp, &ast[i]);
229 
230  for (i = 0; i < NR; ++i)
232 
233  result = m0_bitmap_init(&online, m0_processor_nr_max());
234  M0_ASSERT(result == 0);
235  m0_processors_online(&online);
236 
237  M0_UT_ASSERT(m0_forall(j, NR, passed[j]));
239  (core[j] != 0) == (j < online.b_nr &&
240  m0_bitmap_get(&online, j))));
241  nr = 0;
242  free_func_called = false;
243  M0_SET0(&s[0]);
245  m0_semaphore_down(&sem[0]);
248 
249  nr = 0;
250  M0_SET0(&s[0]);
251  M0_FOM_SIMPLE_POST(&s[0], &reqh, NULL, &simple_tick, NULL, &nr, 1);
252  m0_semaphore_down(&sem[0]);
253  M0_UT_ASSERT(nr == NR);
255  M0_SET0(&s[0]);
258  m0_semaphore_down(&sem[0]);
259  m0_fom_wakeup(&s[0].si_fom);
260  m0_semaphore_down(&sem[0]);
261  M0_UT_ASSERT(nr == 0);
263  M0_SET0(&s[0]);
265  memset(s, 0, sizeof s);
267  &cat_tick, NULL, NULL);
268  for (i = 0; i < ARRAY_SIZE(sem); ++i)
271  for (i = 0; i < ARRAY_SIZE(sem); ++i)
273  m0_bitmap_fini(&online);
276 }
277 M0_EXPORTED(test_locality);
278 
279 static int entered;
280 static int left;
281 static int ticked;
282 static int key0;
283 static int key;
284 static int keyother;
285 static bool has0;
286 
287 static int ctor(void *area, void *cookie)
288 {
289  M0_UT_ASSERT(cookie == &ctor);
290  ((char *)area)[0] = 'x';
291  return 0;
292 }
293 
294 static int enter(struct m0_locality_chore *chore,
295  struct m0_locality *loc, void *place)
296 {
297  char *data = m0_locality_data(key);
298  char *data0 = m0_locality_data(key0);
299  char *dataother = m0_locality_data(keyother);
300 
301  M0_UT_ASSERT(chore->lc_datum == &lock);
302  M0_UT_ASSERT(place != NULL);
303  M0_UT_ASSERT(data != NULL);
304  M0_UT_ASSERT(data[0] == 'x');
305  M0_UT_ASSERT(dataother != NULL);
306  M0_UT_ASSERT(dataother[0] == 0);
307  M0_UT_ASSERT((data0 != NULL) == has0);
309  ++entered;
311  *(long *)place = (long)chore + (long)loc + (long)place;
312  return 0;
313 }
314 
315 static void leave(struct m0_locality_chore *chore,
316  struct m0_locality *loc, void *place)
317 {
318  M0_UT_ASSERT(chore->lc_datum == &lock);
319  M0_UT_ASSERT(place != NULL);
321  M0_UT_ASSERT(*(long *)place == (long)chore + (long)loc + (long)place);
322  ++left;
324 }
325 
326 static void tick(struct m0_locality_chore *chore,
327  struct m0_locality *loc, void *place)
328 {
329  M0_UT_ASSERT(chore->lc_datum == &lock);
330  M0_UT_ASSERT(place != NULL);
332  ++ticked;
334 }
335 
336 static int nosys(struct m0_locality_chore *chore,
337  struct m0_locality *loc, void *place)
338 {
339  return -ENOSYS;
340 }
341 
343 {
344  struct m0_locality_chore chore;
345  int result;
346  int nr_loc;
347  struct m0_locality_chore_ops ops = {
348  .co_enter = &enter,
349  .co_leave = &leave,
350  .co_tick = &tick
351  };
352 
353  memset(passed, 0, sizeof passed);
354  memset(core, 0, sizeof core);
355  memset(sem, 0, sizeof sem);
356  memset(ast, 0, sizeof ast);
357  memset(s, 0, sizeof s);
358  M0_SET0(&reqh);
359  M0_SET0(&lock);
360  M0_SET0(&hoarded);
361  free_func_called = false;
362  expected = 0;
363 
365  nr_loc = m0_fom_dom()->fd_localities_nr;
367  M0_UT_ASSERT(key >= 0);
369  has0 = true;
370  M0_UT_ASSERT(key0 >= 0);
371  M0_UT_ASSERT(key != key0);
373  M0_UT_ASSERT(keyother >= 0);
374  entered = left = ticked = 0;
375  M0_SET0(&chore);
376  result = m0_locality_chore_init(&chore, &ops, &lock,
377  M0_MKTIME(1, 0), 4096);
378  M0_UT_ASSERT(result == 0);
379  M0_UT_ASSERT(entered == nr_loc);
380  M0_UT_ASSERT(left == 0);
381  m0_locality_chore_fini(&chore);
382  M0_UT_ASSERT(entered == nr_loc);
383  M0_UT_ASSERT(left == nr_loc);
384 
385  M0_SET0(&chore);
386  m0_fi_enable_once("m0_alloc", "keep_quiet");
387  result = m0_locality_chore_init(&chore, &ops, &lock,
388  M0_MKTIME(1, 0), 1ULL << 60);
389  M0_UT_ASSERT(result == -ENOMEM);
390 
391  M0_SET0(&chore);
392  ops.co_enter = &nosys;
393  result = m0_locality_chore_init(&chore, &ops, &lock,
394  M0_MKTIME(1, 0), 4096);
395  M0_UT_ASSERT(result == -ENOSYS);
397  has0 = false;
399  ops.co_enter = &enter;
400  entered = left = ticked = 0;
401  M0_SET0(&chore);
402  result = m0_locality_chore_init(&chore, &ops, &lock,
403  M0_MKTIME(1, 0), 4096);
404  M0_UT_ASSERT(result == 0);
405  M0_UT_ASSERT(entered == nr_loc);
406  M0_UT_ASSERT(left == 0);
407  m0_locality_chore_fini(&chore);
408  M0_UT_ASSERT(entered == nr_loc);
409  M0_UT_ASSERT(left == nr_loc);
411  m0_fi_enable_once("m0_alloc", "keep_quiet");
412  result = m0_locality_data_alloc(1ULL << 60, NULL, NULL, NULL);
413  M0_UT_ASSERT(result == -ENOMEM);
417 }
418 M0_EXPORTED(test_locality_chore);
419 
420 /*
421  * Local variables:
422  * c-indentation-style: "K&R"
423  * c-basic-offset: 8
424  * tab-width: 8
425  * fill-column: 80
426  * scroll-step: 1
427  * End:
428  */
static void m0_atomic64_inc(struct m0_atomic64 *a)
static size_t nr
Definition: dump.c:1505
M0_INTERNAL void m0_fom_wakeup(struct m0_fom *fom)
Definition: fom.c:532
M0_INTERNAL int m0_reqh_service_start(struct m0_reqh_service *service)
Definition: reqh_service.c:343
M0_INTERNAL int m0_bitmap_init(struct m0_bitmap *map, size_t nr)
Definition: bitmap.c:86
M0_INTERNAL void m0_reqh_services_terminate(struct m0_reqh *reqh)
Definition: reqh.c:675
static void fom_simple_svc_start(void)
Definition: locality.c:50
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
static void tick(struct m0_locality_chore *chore, struct m0_locality *loc, void *place)
Definition: locality.c:326
static bool passed[NR]
Definition: locality.c:40
M0_INTERNAL struct m0_locality * m0_locality_get(uint64_t value)
Definition: locality.c:156
static int entered
Definition: locality.c:279
#define NULL
Definition: misc.h:38
M0_INTERNAL void m0_bitmap_fini(struct m0_bitmap *map)
Definition: bitmap.c:97
void * m0_locality_data(int key)
Definition: locality.c:474
static int semisimple_tick(struct m0_fom *fom, int *x, int *phase)
Definition: locality.c:164
void(* sa_cb)(struct m0_sm_group *grp, struct m0_sm_ast *)
Definition: sm.h:506
static struct m0_sm_conf semisimple_conf
Definition: locality.c:158
static bool x
Definition: sm.c:168
#define M0_REQH_INIT(reqh,...)
Definition: reqh.h:262
Definition: sm.h:350
static struct m0_sm_state_descr semisimple_phases[]
Definition: locality.c:134
static struct m0_sm_group * grp
Definition: bytecount.c:38
M0_INTERNAL m0_processor_nr_t m0_processor_nr_max(void)
Definition: processor.c:1093
M0_INTERNAL void m0_sm_ast_post(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: sm.c:135
static struct m0_reqh reqh
Definition: locality.c:45
#define M0_FID_INIT(container, key)
Definition: fid.h:84
static void leave(struct m0_locality_chore *chore, struct m0_locality *loc, void *place)
Definition: locality.c:315
static struct m0_semaphore sem[NR]
Definition: locality.c:43
struct m0_bufvec data
Definition: di.c:40
void free_func(struct m0_fom_simple *sfom)
Definition: locality.c:122
static int cat_tick(struct m0_fom *fom, void *null, int *__unused)
Definition: locality.c:191
#define M0_BITS(...)
Definition: misc.h:236
static int left
Definition: locality.c:280
Definition: sm.h:504
M0_INTERNAL m0_processor_nr_t m0_processor_id_get(void)
Definition: processor.c:1139
#define container_of(ptr, type, member)
Definition: misc.h:33
#define M0_SET0(obj)
Definition: misc.h:64
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
M0_INTERNAL void m0_reqh_fini(struct m0_reqh *reqh)
Definition: reqh.c:320
static uint64_t core[NR]
Definition: locality.c:41
M0_INTERNAL struct m0_reqh_service_type * m0_reqh_service_type_find(const char *sname)
Definition: reqh_service.c:168
static bool has0
Definition: locality.c:285
static struct m0_sm_ast ast[NR]
Definition: locality.c:44
static int expected
Definition: locality.c:102
void m0_locality_data_free(int key)
Definition: locality.c:463
int i
Definition: dir.c:1033
size_t si_locality
Definition: fom_simple.h:125
static int keyother
Definition: locality.c:284
static int key
Definition: locality.c:283
static bool free_func_called
Definition: locality.c:48
static const struct socktype stype[]
Definition: sock.c:1156
static struct m0_fom_simple s[NR]
Definition: locality.c:46
#define M0_ASSERT(cond)
struct m0_reqh * m0_ut__reqh_init(void)
Definition: locality.c:67
const char * scf_name
Definition: sm.h:352
static int key0
Definition: locality.c:282
M0_INTERNAL bool m0_reqh_service_invariant(const struct m0_reqh_service *svc)
Definition: reqh_service.c:143
M0_INTERNAL void m0_reqh_shutdown(struct m0_reqh *reqh)
Definition: reqh.c:636
M0_INTERNAL int m0_semaphore_init(struct m0_semaphore *semaphore, unsigned value)
Definition: semaphore.c:38
M0_INTERNAL void m0_processors_online(struct m0_bitmap *map)
Definition: processor.c:1113
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
#define M0_POST(cond)
int m0_locality_chore_init(struct m0_locality_chore *chore, const struct m0_locality_chore_ops *ops, void *datum, m0_time_t interval, size_t datasize)
Definition: locality.c:270
M0_INTERNAL int m0_reqh_service_allocate(struct m0_reqh_service **out, const struct m0_reqh_service_type *stype, struct m0_reqh_context *rctx)
Definition: reqh_service.c:185
Definition: reqh.h:94
Definition: dump.c:103
static struct m0_atomic64 hoarded
Definition: locality.c:47
void m0_ut__reqh_fini(void)
Definition: locality.c:84
M0_INTERNAL void m0_reqh_service_init(struct m0_reqh_service *service, struct m0_reqh *reqh, const struct m0_fid *fid)
Definition: reqh_service.c:428
static int ctor(void *area, void *cookie)
Definition: locality.c:287
static struct m0_mutex lock
Definition: locality.c:42
M0_INTERNAL void m0_fom_simple_hoard(struct m0_fom_simple *cat, size_t nr, struct m0_reqh *reqh, struct m0_sm_conf *conf, int(*tick)(struct m0_fom *, void *, int *), void(*free)(struct m0_fom_simple *sfom), void *data)
Definition: fom_simple.c:81
M0_INTERNAL struct m0_locality * m0_locality_here(void)
Definition: locality.c:146
static int enter(struct m0_locality_chore *chore, struct m0_locality *loc, void *place)
Definition: locality.c:294
M0_INTERNAL void m0_reqh_idle_wait(struct m0_reqh *reqh)
Definition: reqh.c:606
struct m0_fom si_fom
Definition: fom_simple.h:120
static int64_t m0_atomic64_get(const struct m0_atomic64 *a)
#define m0_forall(var, nr,...)
Definition: misc.h:112
Definition: fom.h:481
static int tick_once(struct m0_fom *fom, int *x, int *__unused)
Definition: locality.c:117
void m0_locality_chore_fini(struct m0_locality_chore *chore)
Definition: locality.c:296
M0_INTERNAL void m0_reqh_start(struct m0_reqh *reqh)
Definition: reqh.c:711
const char * sd_name
Definition: sm.h:383
static void _cb0(struct m0_sm_group *grp, struct m0_sm_ast *a)
Definition: locality.c:91
static int ticked
Definition: locality.c:281
void test_locality(void)
Definition: locality.c:204
Definition: locality.c:36
M0_INTERNAL void m0_semaphore_fini(struct m0_semaphore *semaphore)
Definition: semaphore.c:45
M0_INTERNAL struct m0_fom_domain * m0_fom_dom(void)
Definition: locality.c:575
size_t lo_idx
Definition: locality.h:68
M0_INTERNAL bool m0_bitmap_get(const struct m0_bitmap *map, size_t idx)
Definition: bitmap.c:105
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
#define IS_IN_ARRAY(idx, array)
Definition: misc.h:311
static void m0_fi_enable_once(const char *func, const char *tag)
Definition: finject.h:301
#define M0_MKTIME(secs, ns)
Definition: time.h:86
int m0_locality_data_alloc(size_t nob, int(*ctor)(void *, void *), void(*dtor)(void *, void *), void *datum)
Definition: locality.c:442
static int nosys(struct m0_locality_chore *chore, struct m0_locality *loc, void *place)
Definition: locality.c:336
M0_INTERNAL void m0_semaphore_down(struct m0_semaphore *semaphore)
Definition: semaphore.c:49
size_t b_nr
Definition: bitmap.h:44
M0_INTERNAL void m0_semaphore_up(struct m0_semaphore *semaphore)
Definition: semaphore.c:65
struct m0_fom_ops ops
Definition: io_foms.c:623
Definition: mutex.h:47
void test_locality_chore(void)
Definition: locality.c:342
#define M0_FOM_SIMPLE_POST(s, r, c, t, f, d, l)
Definition: fom_simple.h:165
size_t fd_localities_nr
Definition: fom.h:333
static int simple_tick(struct m0_fom *fom, int *x, int *__unused)
Definition: locality.c:103
static struct m0_reqh_service * service[REQH_IN_UT_MAX]
Definition: long_lock_ut.c:46
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
struct m0_fid g_process_fid
Definition: ut.c:689
#define M0_UT_ASSERT(a)
Definition: ut.h:46
static void m0_atomic64_set(struct m0_atomic64 *a, int64_t num)
Definition: idx_mock.c:47