Motr  M0
read.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 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 /*
24  * Client API system tests to check if Client API matches its
25  * specifications.
26  */
27 
28 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_CLIENT
29 #include "lib/trace.h"
30 
31 #include "motr/client.h"
32 #include "motr/st/st.h"
33 #include "motr/st/st_misc.h"
34 #include "motr/st/st_assert.h"
35 
36 #include "lib/memory.h"
37 
39 extern struct m0_addb_ctx m0_addb_ctx;
41 static uint64_t layout_id;
42 
43 enum { MAX_READ_OID_NUM = 256 };
44 
45 static int read_oid_num = 0;
47 
48 static struct m0_uint128 read_oid_get(int idx)
49 {
50  struct m0_uint128 oid;
51 
52  /* return non-existing oid */
53  if (idx < 0 || idx >= MAX_READ_OID_NUM) {
54  oid_get(&oid);
55  return oid;
56  }
57 
58  return read_oids[idx];
59 }
60 
61 static int create_objs(int nr_objs)
62 {
63  int i;
64  int rc;
65  struct m0_uint128 id;
66  struct m0_op *ops[1] = {NULL};
67  struct m0_obj obj;
68 
70 
71  for (i = 0; i < nr_objs; i++) {
72  memset(&obj, 0, sizeof obj);
73  ops[0] = NULL;
74 
75  /* get oid */
76  oid_get(&id);
77 
78  /* Create an entity */
81  &id, layout_id);
82 
83  st_entity_create(NULL, &obj.ob_entity, &ops[0]);
84 
85  st_op_launch(ops, 1);
86 
87  /* Wait for op to complete */
89  M0_OS_STABLE),
91  if (rc < 0)
92  return rc;
93 
94  M0_ASSERT(rc == 0);
95  M0_ASSERT(ops[0]->op_sm.sm_state == M0_OS_STABLE);
96  M0_ASSERT(ops[0]->op_sm.sm_rc == 0);
97 
98  /* fini and release */
99  st_op_fini(ops[0]);
100  st_op_free(ops[0]);
101  st_entity_fini(&obj.ob_entity);
102 
103  /* Save the created oid */
105  read_oid_num++;
106  }
107 
108  return 0;
109 }
110 
111 /*
112  * Fill those pre-created objects with some value
113  */
114 enum { CHAR_NUM = 6 };
115 static char pattern[CHAR_NUM] = {'C', 'L', 'O', 'V', 'I', 'S'};
116 
117 static int write_objs(void)
118 {
119  int i;
120  int rc;
121  int blk_cnt;
122  int blk_size;
123  char value;
124  uint64_t last_index;
125  struct m0_uint128 id;
126  struct m0_obj obj;
127  struct m0_op *ops[1] = {NULL};
128  struct m0_indexvec ext;
129  struct m0_bufvec data;
130  struct m0_bufvec attr;
131 
133 
134  /* Prepare the data with 'value' */
135  blk_cnt = 4;
136  blk_size = unit_size;
137 
138  rc = m0_bufvec_alloc(&data, blk_cnt, blk_size);
139  if (rc != 0)
140  return rc;
141 
142  for (i = 0; i < blk_cnt; i++) {
143  /*
144  * The pattern written to object has to match
145  * to those in read tests
146  */
147  value = pattern[i % CHAR_NUM];
148  memset(data.ov_buf[i], value, blk_size);
149  }
150 
151  /* Prepare indexvec for write */
152  rc = m0_bufvec_alloc(&attr, blk_cnt, 1);
153  if(rc != 0) return rc;
154 
155  rc = m0_indexvec_alloc(&ext, blk_cnt);
156  if (rc != 0) return rc;
157 
158  last_index = 0;
159  for (i = 0; i < blk_cnt; i++) {
160  ext.iv_index[i] = last_index ;
161  ext.iv_vec.v_count[i] = blk_size;
162  last_index += blk_size;
163 
164  /* we don't want any attributes */
165  attr.ov_vec.v_count[i] = 0;
166  }
167 
168  /* Write to objects one by one */
169  for (i = 0; i < read_oid_num; i++) {
170  memset(&obj, 0, sizeof obj);
171  ops[0] = NULL;
172 
173  /* Get object id. */
174  id = read_oids[i];
175 
176  /* Set the object entity we want to write */
177  st_obj_init(
179  &id, layout_id);
180 
181  st_entity_open(&obj.ob_entity);
182 
183  /* Create the write request */
184  st_obj_op(&obj, M0_OC_WRITE, &ext, &data, NULL, 0, 0, &ops[0]);
185 
186  /* Launch the write request*/
187  st_op_launch(ops, 1);
188 
189  /* wait */
191  M0_OS_STABLE),
192  M0_TIME_NEVER);
193  if (rc < 0) break;
194 
195  /* fini and release */
196  st_op_fini(ops[0]);
197  st_op_free(ops[0]);
198  st_entity_fini(&obj.ob_entity);
199  }
202  m0_indexvec_free(&ext);
203  return rc;
204 }
205 
210 void read_block_has_val(struct m0_bufvec *data, int block_idx, char val)
211 {
212  int i;
213 
214  for(i = 0; i < data->ov_vec.v_count[block_idx]; i++)
215  ST_ASSERT_FATAL(((char *)data->ov_buf[block_idx])[i] == val);
216 }
217 
221 static void read_one_block(void)
222 {
223  int rc;
224  struct m0_op *ops[1] = {NULL};
225  struct m0_obj obj;
226  struct m0_uint128 id;
227  struct m0_indexvec ext;
228  struct m0_bufvec data;
229  struct m0_bufvec attr;
230 
232 
233  /* we want to read 4K from the beginning of the object */
234  rc = m0_indexvec_alloc(&ext, 1);
235  if (rc != 0)
236  return;
237 
238  ext.iv_index[0] = 0;
240  ST_ASSERT_FATAL(ext.iv_vec.v_nr == 1);
241 
242  /*
243  * this allocates 1 * 4K buffers for data, and initialises
244  * the bufvec for us.
245  */
247  if (rc != 0)
248  return;
249  rc = m0_bufvec_alloc(&attr, 1, 1);
250  if(rc != 0)
251  return;
252 
253  /* we don't want any attributes */
254  attr.ov_vec.v_count[0] = 0;
255 
256  /* Get the id of an existing object (written via m0t1fs). */
257  id = read_oid_get(0);
258  M0_SET0(&obj);
260  &id, layout_id);
261 
262  st_entity_open(&obj.ob_entity);
263 
264  /* Create the read request */
265  st_obj_op(&obj, M0_OC_READ, &ext, &data, NULL, 0, 0, &ops[0]);
266  ST_ASSERT_FATAL(rc == 0);
267  ST_ASSERT_FATAL(ops[0] != NULL);
268  ST_ASSERT_FATAL(ops[0]->op_sm.sm_rc == 0);
269 
271 
272  /* wait */
274  M0_OS_STABLE),
275  M0_TIME_NEVER);
276  ST_ASSERT_FATAL(rc == 0);
277  ST_ASSERT_FATAL(ops[0]->op_sm.sm_state == M0_OS_STABLE);
278  ST_ASSERT_FATAL(ops[0]->op_sm.sm_rc == 0);
279 
280  /* check if correct data is returned*/
282 
283  st_op_fini(ops[0]);
284  st_op_free(ops[0]);
285 
286  st_entity_fini(&obj.ob_entity);
287 
288  m0_indexvec_free(&ext);
291 }
292 
296 static void read_multiple_blocks(void)
297 {
298  int rc;
299  struct m0_op *ops[1] = {NULL};
300  struct m0_obj obj;
301  struct m0_uint128 id;
302  struct m0_indexvec ext;
303  struct m0_bufvec data;
304  struct m0_bufvec attr;
305 
307 
308  /* we want to read 3x 4K from the beginning of the object */
309  rc = m0_indexvec_alloc(&ext, 3);
310  if (rc != 0)
311  return;
312 
313  /* Extent indexes and lengths */
314  ext.iv_index[0] = 0;
320 
321  /*
322  * this allocates 3 * 4K buffers for data, and initialises
323  * the bufvec for us.
324  */
326  if (rc != 0)
327  return;
328  rc = m0_bufvec_alloc(&attr, 3, 1);
329  if(rc != 0)
330  return;
331 
332  /* we don't want any attributes */
333  attr.ov_vec.v_count[0] = 0;
334  attr.ov_vec.v_count[1] = 0;
335  attr.ov_vec.v_count[2] = 0;
336 
337  /* Get the id of an existing object. */
338  M0_SET0(&obj);
339  id = read_oid_get(0);
341  &id, layout_id);
342 
343  st_entity_open(&obj.ob_entity);
344 
345  /* Create the read request */
346  st_obj_op(&obj, M0_OC_READ, &ext, &data, NULL, 0, 0, &ops[0]);
347  ST_ASSERT_FATAL(rc == 0);
348  ST_ASSERT_FATAL(ops[0] != NULL);
349  ST_ASSERT_FATAL(ops[0]->op_sm.sm_rc == 0);
350 
352 
353  /* wait */
355  M0_OS_STABLE),
356  M0_TIME_NEVER);
357  ST_ASSERT_FATAL(rc == 0);
358  ST_ASSERT_FATAL(ops[0]->op_sm.sm_state == M0_OS_STABLE);
359  ST_ASSERT_FATAL(ops[0]->op_sm.sm_rc == 0);
360 
361  /* check if correct data is returned*/
365 
366 
367  st_op_fini(ops[0]);
368  st_op_free(ops[0]);
369 
370  st_entity_fini(&obj.ob_entity);
371 
372  m0_indexvec_free(&ext);
375 }
376 
377 
383 {
384  int rc;
385  struct m0_op *ops[1] = {NULL};
386  struct m0_obj obj;
387  struct m0_uint128 id;
388  struct m0_indexvec ext;
389  struct m0_bufvec data;
390  struct m0_bufvec attr;
391  void *stashed_buffers[2];
392 
394 
395  /* we want to read 2 units starting with the second blockof the object */
396  rc = m0_indexvec_alloc(&ext, 2);
397  if (rc != 0)
398  return;
399 
400  /* Extent indexes and lengths */
401  ext.iv_index[0] = unit_size;
402  ext.iv_vec.v_count[0] = unit_size;
403  ext.iv_index[1] = 2 * unit_size;
404  ext.iv_vec.v_count[1] = unit_size;
405 
406  /*
407  * this allocates 2 * unit_size buffers for data, and initialises
408  * the bufvec for us.
409  */
411  if (rc != 0)
412  return;
413  rc = m0_bufvec_alloc(&attr, 2, 1);
414  if(rc != 0)
415  return;
416 
417  /*
418  * Stash the m0_bufvec_alloc'd buffers, and replace them with
419  * aligned buffers.
420  */
421  stashed_buffers[0] = data.ov_buf[0];
422  data.ov_buf[0] = m0_alloc_aligned(4096, 12);
424  stashed_buffers[1] = data.ov_buf[1];
425  data.ov_buf[1] = m0_alloc_aligned(4096, 12);
427 
428  /* we don't want any attributes */
429  attr.ov_vec.v_count[0] = 0;
430  attr.ov_vec.v_count[1] = 0;
431 
432  /* Get the id of an existing object. */
433  M0_SET0(&obj);
434  id = read_oid_get(0);
436  &id, layout_id);
437 
438  st_entity_open(&obj.ob_entity);
439 
440  /* Create the read request */
441  st_obj_op(&obj, M0_OC_READ, &ext, &data, NULL, 0, 0, &ops[0]);
442  ST_ASSERT_FATAL(rc == 0);
443  ST_ASSERT_FATAL(ops[0] != NULL);
444  ST_ASSERT_FATAL(ops[0]->op_sm.sm_rc == 0);
445 
447 
448  /* wait */
450  M0_OS_STABLE),
451  M0_TIME_NEVER);
452  ST_ASSERT_FATAL(rc == 0);
453  ST_ASSERT_FATAL(ops[0]->op_sm.sm_state == M0_OS_STABLE);
454  ST_ASSERT_FATAL(ops[0]->op_sm.sm_rc == 0);
455 
456  /* check if correct data is returned*/
459 
460  st_op_fini(ops[0]);
461  st_op_free(ops[0]);
462 
463  st_entity_fini(&obj.ob_entity);
464 
465  /* Swap the buffers back */
466  m0_free_aligned(data.ov_buf[0], 4096, 12);
467  data.ov_buf[0] = stashed_buffers[0];
468  m0_free_aligned(data.ov_buf[1], 4096, 12);
469  data.ov_buf[1] = stashed_buffers[1];
470 
471  m0_indexvec_free(&ext);
474 }
475 
476 static void read_objs_in_parallel(void)
477 {
478  int i;
479  int rc = 0;
480  int nr_objs = read_oid_num;
481  struct m0_uint128 id;
482  struct m0_obj *objs;
483  struct m0_op **ops;
484  struct m0_indexvec *ext;
485  struct m0_bufvec *data;
486  struct m0_bufvec *attr;
487 
489 
490  /* Allocate memory object array */
491  MEM_ALLOC_ARR(objs, nr_objs);
492  ST_ASSERT_FATAL (objs != NULL)
493 
494  /* Setup bufvec, indexvec and ops for READs */
495  MEM_ALLOC_ARR(ops, nr_objs);
496  MEM_ALLOC_ARR(ext, nr_objs);
497  MEM_ALLOC_ARR(data, nr_objs);
498  MEM_ALLOC_ARR(attr, nr_objs);
499  if (ops == NULL || ext == NULL || data == NULL || attr == NULL)
500  goto CLEANUP;
501 
502  for (i = 0; i < nr_objs; i++) {
503  ops[i] = NULL;
504  memset(&ext[i], 0, sizeof ext[i]);
505  memset(&data[i], 0, sizeof data[i]);
506  memset(&attr[i], 0, sizeof attr[i]);
507  }
508 
509  for (i = 0; i < nr_objs; i++) {
510  if (m0_indexvec_alloc(&ext[i], 1) ||
511  m0_bufvec_alloc(&data[i], 1, unit_size) ||
512  m0_bufvec_alloc(&attr[i], 1, 1))
513  {
514  rc = -ENOMEM;
515  goto CLEANUP;
516  }
517 
518  ext[i].iv_index[0] = 0;
519  ext[i].iv_vec.v_count[0] = unit_size;
520  attr[i].ov_vec.v_count[0] = 0;
521  }
522 
523  /* Create and launch write requests */
524  for (i = 0; i < nr_objs; i++) {
525  M0_SET0(&objs[i]);
526  id = read_oid_get(i);
527 
529  &id, layout_id);
530 
531  st_entity_open(&objs[i].ob_entity);
532 
533  st_obj_op(&objs[i], M0_OC_READ,
534  &ext[i], &data[i], NULL, 0, 0, &ops[i]);
535  if (ops[i] == NULL)
536  break;
537  }
538  if (i != nr_objs) goto CLEANUP;
539 
540  st_op_launch(ops, nr_objs);
541 
542  /* Wait for write to finish */
543  for (i = 0; i < nr_objs; i++) {
544  rc = st_op_wait(ops[i],
546  M0_OS_STABLE),
547  M0_TIME_NEVER);
548  ST_ASSERT_FATAL(rc == 0);
550  ops[i]->op_sm.sm_state == M0_OS_STABLE);
551  ST_ASSERT_FATAL(ops[i]->op_sm.sm_rc == 0);
552 
553  st_op_fini(ops[i]);
554  st_op_free(ops[i]);
555  }
556 
557 CLEANUP:
558  for (i = 0; i < nr_objs; i++) {
559  if (ops[i] != NULL)
560  st_entity_fini(&objs[i].ob_entity);
561  }
562  mem_free(objs);
563 
564  for (i = 0; i < nr_objs; i++) {
565  if (ext != NULL && ext[i].iv_vec.v_nr != 0)
566  m0_indexvec_free(&ext[i]);
567  if (data != NULL && data[i].ov_buf != NULL)
568  m0_bufvec_free(&data[i]);
569  if (attr != NULL && attr[i].ov_buf != NULL)
570  m0_bufvec_free(&attr[i]);
571  }
572 
573  if (ops != NULL) mem_free(ops);
574  if (ext != NULL) mem_free(ext);
575  if (data != NULL) mem_free(data);
576  if (attr != NULL) mem_free(attr);
577 }
578 
582 static int st_read_suite_init(void)
583 {
584  int rc = 0;
585  int nr_objs;
586 
587  /*
588  * Retrieve the uber realm. We don't need to open this,
589  * as realms are not actually implemented yet
590  */
593  st_get_instance());
595 
596  if (rc != 0) {
597  console_printf("Failed to open uber realm\n");
598  goto EXIT;
599  }
600 
602 
603  /*
604  * Create objects for tests including a few more used
605  * in read_after_delete test.
606  */
607  nr_objs = 1;
608  rc = create_objs(nr_objs + 1);
609  if (rc < 0) {
610  console_printf("Failed to create objects for READ tests\n");
611  goto EXIT;
612  }
613 
614  rc = write_objs();
615  if (rc < 0)
616  console_printf("Failed to write objects for READ tests\n");
617 
618 EXIT:
619  return rc;
620 }
621 
625 static int st_read_suite_fini(void)
626 {
627  return 0;
628 }
629 
631  .ss_name = "m0_read_st",
632  .ss_init = st_read_suite_init,
633  .ss_fini = st_read_suite_fini,
634  .ss_tests = {
635  { "read_one_block",
636  &read_one_block },
637  { "read_multiple_blocks",
639  { "read_multiple_blocks_into_aligned_buffers",
641  { "read_objs_in_parallel",
643  { NULL, NULL }
644  }
645 };
646 
647 #undef M0_TRACE_SUBSYSTEM
648 
649 /*
650  * Local variables:
651  * c-indentation-style: "K&R"
652  * c-basic-offset: 8
653  * tab-width: 8
654  * fill-column: 80
655  * scroll-step: 1
656  * End:
657  */
uint64_t id
Definition: cob.h:2380
int st_entity_create(struct m0_fid *pool, struct m0_entity *entity, struct m0_op **op)
Definition: api.c:71
void st_op_free(struct m0_op *op)
Definition: api.c:147
Definition: client.h:788
M0_INTERNAL int m0_indexvec_alloc(struct m0_indexvec *ivec, uint32_t len)
Definition: vec.c:532
#define NULL
Definition: misc.h:38
Definition: idx_mock.c:52
const m0_time_t M0_TIME_NEVER
Definition: time.c:108
struct m0_vec ov_vec
Definition: vec.h:147
struct m0_bufvec data
Definition: di.c:40
int const char const void * value
Definition: dir.c:325
uint64_t m0_client_layout_id(const struct m0_client *instance)
Definition: obj.c:859
M0_INTERNAL void m0_indexvec_free(struct m0_indexvec *ivec)
Definition: vec.c:553
M0_INTERNAL void m0_free_aligned(void *data, size_t size, unsigned shift)
Definition: memory.c:192
#define M0_BITS(...)
Definition: misc.h:236
#define M0_SET0(obj)
Definition: misc.h:64
const struct m0_uint128 M0_UBER_REALM
Definition: client.c:85
static int st_read_suite_fini(void)
Definition: read.c:625
static void read_multiple_blocks(void)
Definition: read.c:296
#define ST_ASSERT_FATAL(a)
Definition: st_assert.h:31
void ** ov_buf
Definition: vec.h:149
static struct foo * obj
Definition: tlist.c:302
M0_INTERNAL int m0_bufvec_alloc(struct m0_bufvec *bufvec, uint32_t num_segs, m0_bcount_t seg_size)
Definition: vec.c:220
struct m0_vec iv_vec
Definition: vec.h:139
M0_INTERNAL void m0_bufvec_free(struct m0_bufvec *bufvec)
Definition: vec.c:395
m0_bindex_t * iv_index
Definition: vec.h:141
struct st_suite st_suite_m0_read
Definition: read.c:630
int i
Definition: dir.c:1033
static uint64_t layout_id
Definition: read.c:41
struct m0_realm co_realm
Definition: client.h:881
Definition: client.h:641
static void attr(struct m0_addb2__context *ctx, const uint64_t *v, char *buf)
Definition: dump.c:949
void st_container_init(struct m0_container *con, struct m0_realm *parent, const struct m0_uint128 *id, struct m0_client *instance)
Definition: api.c:34
static char pattern[CHAR_NUM]
Definition: read.c:115
struct m0_entity re_entity
Definition: client.h:871
int oid_get(struct m0_uint128 *oid)
Definition: oid.c:373
struct m0_container st_read_container
Definition: read.c:38
#define M0_ASSERT(cond)
Definition: st.h:83
static int create_objs(int nr_objs)
Definition: read.c:61
static void read_objs_in_parallel(void)
Definition: read.c:476
static int read_oid_num
Definition: read.c:45
static void read_multiple_blocks_into_aligned_buffers(void)
Definition: read.c:382
static uint32_t unit_size
Definition: read.c:40
uint32_t v_nr
Definition: vec.h:51
int32_t sm_rc
Definition: sm.h:336
m0_bcount_t * v_count
Definition: vec.h:53
void console_printf(const char *fmt,...)
Definition: st_misc.c:155
static void mem_free(const struct m0_be_btree *btree, struct m0_be_tx *tx, void *ptr)
Definition: btree.c:102
static struct m0_uint128 read_oid_get(int idx)
Definition: read.c:48
void st_obj_init(struct m0_obj *obj, struct m0_realm *parent, const struct m0_uint128 *id, uint64_t layout_id)
Definition: api.c:42
static int write_objs(void)
Definition: read.c:117
static void read_one_block(void)
Definition: read.c:221
void st_obj_op(struct m0_obj *obj, enum m0_obj_opcode opcode, struct m0_indexvec *ext, struct m0_bufvec *data, struct m0_bufvec *attr, uint64_t mask, uint32_t flags, struct m0_op **op)
Definition: api.c:100
#define MEM_ALLOC_ARR(arr, nr)
Definition: st_misc.h:80
void read_block_has_val(struct m0_bufvec *data, int block_idx, char val)
Definition: read.c:210
Definition: read.c:114
struct m0_client * st_get_instance()
Definition: st.c:57
#define M0_CLIENT_THREAD_ENTER
void st_op_launch(struct m0_op **op, uint32_t nr)
Definition: api.c:129
void st_entity_fini(struct m0_entity *entity)
Definition: api.c:94
const char * ss_name
Definition: st.h:85
static struct m0_uint128 read_oids[MAX_READ_OID_NUM]
Definition: read.c:46
void st_entity_open(struct m0_entity *entity)
Definition: api.c:153
struct m0_sm en_sm
Definition: client.h:732
static int st_read_suite_init(void)
Definition: read.c:582
M0_INTERNAL void * m0_alloc_aligned(size_t size, unsigned shift)
Definition: memory.c:168
struct m0_fom_ops ops
Definition: io_foms.c:623
struct m0_addb_ctx m0_addb_ctx
int32_t st_op_wait(struct m0_op *op, uint64_t bits, m0_time_t to)
Definition: api.c:136
void st_op_fini(struct m0_op *op)
Definition: api.c:142
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
Definition: vec.h:145