Motr  M0
extmap.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 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_EXTMAP
24 #include "lib/trace.h"
25 
26 #include "be/extmap.h"
27 #include "lib/vec.h"
28 #include "lib/errno.h"
29 #include "lib/arith.h" /* M0_3WAY */
30 #include "lib/misc.h"
31 #include "lib/finject.h"
32 #include "lib/memory.h"
33 #include "lib/cksum_utils.h"
34 #include "lib/cksum.h"
35 #include "format/format.h" /* m0_format_header_pack */
36 
37 /* max data units that can be sent in a request */
38 #define MAX_DUS 8
39 
85 /*
86 static void key_print(const struct m0_be_emap_key *k)
87 {
88  printf(U128X_F":%08lx", U128_P(&k->ek_prefix), k->ek_offset);
89 }
90 */
91 
92 static int be_emap_cmp(const void *key0, const void *key1);
93 static m0_bcount_t be_emap_ksize(const void* k);
94 static m0_bcount_t be_emap_vsize(const void* d);
95 static int emap_it_pack(struct m0_be_emap_cursor *it,
96  void (*btree_func)(struct m0_be_btree *btree,
97  struct m0_be_tx *tx,
98  struct m0_be_op *op,
99  const struct m0_buf *key,
100  const struct m0_buf *val),
101  struct m0_be_tx *tx);
102 static bool emap_it_prefix_ok(const struct m0_be_emap_cursor *it);
103 static int emap_it_open(struct m0_be_emap_cursor *it);
104 static void emap_it_init(struct m0_be_emap_cursor *it,
105  const struct m0_uint128 *prefix,
107  struct m0_be_emap *map);
108 static void be_emap_close(struct m0_be_emap_cursor *it);
109 static int emap_it_get(struct m0_be_emap_cursor *it);
110 static int be_emap_lookup(struct m0_be_emap *map,
111  const struct m0_uint128 *prefix,
113  struct m0_be_emap_cursor *it);
114 static int be_emap_next(struct m0_be_emap_cursor *it);
115 static int be_emap_prev(struct m0_be_emap_cursor *it);
116 static bool be_emap_invariant(struct m0_be_emap_cursor *it);
117 static int emap_extent_update(struct m0_be_emap_cursor *it,
118  struct m0_be_tx *tx,
119  const struct m0_be_emap_seg *es);
120 static int be_emap_split(struct m0_be_emap_cursor *it,
121  struct m0_be_tx *tx,
122  struct m0_indexvec *vec,
124  struct m0_buf *cksum);
125 static bool be_emap_caret_invariant(const struct m0_be_emap_caret *car);
126 
127 static const struct m0_be_btree_kv_ops be_emap_ops = {
129  .ko_ksize = be_emap_ksize,
130  .ko_vsize = be_emap_vsize,
131  .ko_compare = be_emap_cmp
132 };
133 
134 static struct m0_rwlock *emap_rwlock(struct m0_be_emap *emap)
135 {
136  return &emap->em_lock.bl_u.rwlock;
137 }
138 
139 static void emap_dump(struct m0_be_emap_cursor *it)
140 {
141  int i;
142  int rc;
143  struct m0_be_emap_cursor *scan;
144  struct m0_uint128 *prefix = &it->ec_key.ek_prefix;
145  struct m0_be_emap_seg *seg;
146 
148  if (scan == NULL)
149  return;
150  seg = &scan->ec_seg;
151 
154  M0_ASSERT(rc == 0);
155 
157  for (i = 0; ; ++i) {
158  M0_LOG(M0_DEBUG, "\t%5.5i %16lx .. %16lx: %16lx %10lx", i,
159  (unsigned long)seg->ee_ext.e_start,
160  (unsigned long)seg->ee_ext.e_end,
161  (unsigned long)m0_ext_length(&seg->ee_ext),
162  (unsigned long)seg->ee_val);
164  break;
165  rc = be_emap_next(scan);
166  M0_ASSERT(rc == 0);
167  }
170 
171  m0_free(scan);
172 }
173 
174 static void emap_key_init(struct m0_be_emap_key *key)
175 {
176  m0_format_header_pack(&key->ek_header, &(struct m0_format_tag){
177  .ot_version = M0_BE_EMAP_KEY_FORMAT_VERSION,
178  .ot_type = M0_FORMAT_TYPE_BE_EMAP_KEY,
179  .ot_footer_offset = offsetof(struct m0_be_emap_key, ek_footer)
180  });
182 }
183 
184 static void emap_rec_init(struct m0_be_emap_rec *rec)
185 {
187  .ot_version = M0_BE_EMAP_REC_FORMAT_VERSION,
188  .ot_type = M0_FORMAT_TYPE_BE_EMAP_REC,
192  .ot_footer_offset = offsetof(struct m0_be_emap_rec,
193  er_footer)
194  + rec->er_cksum_nob
195  });
197 }
198 
199 M0_INTERNAL int m0_be_emap_dump(struct m0_be_emap *map)
200 {
201  struct m0_be_emap_cursor *it;
202  struct m0_be_emap_seg *seg = NULL;
203  m0_bcount_t nr_segs = 0;
204  m0_bcount_t nr_cobs = 0;
205  int rc = 0;
206  struct m0_uint128 prefix;
207 
208  M0_ALLOC_PTR(it);
209  if (it == NULL)
210  return M0_ERR(-ENOMEM);
211 
213 
214  prefix = M0_UINT128(0, 0);
215  rc = be_emap_lookup(map, &prefix, 0, it);
216  if (rc == -ESRCH) {
217  prefix = it->ec_seg.ee_pre;
218  rc = be_emap_lookup(map, &prefix, 0, it);
219  }
220  if (rc != 0)
221  goto err;
222 
223  do {
227  ++nr_segs;
229  ++nr_cobs;
230  rc = be_emap_next(it);
231  } while (rc == 0 || rc == -ESRCH);
232 
233  be_emap_close(it);
234  err:
236 
237  if (seg != NULL)
238  M0_LOG(M0_DEBUG, "%p %" PRIx64 " %u %lu", map,
239  seg->ee_pre.u_hi, (unsigned)nr_cobs,
240  (unsigned long)nr_segs);
241 
242  m0_free(it);
243 
244  if (rc == -ENOENT)
245  return M0_RC(0);
246 
247  return M0_ERR(rc);
248 }
249 
250 static void delete_wrapper(struct m0_be_btree *btree, struct m0_be_tx *tx,
251  struct m0_be_op *op, const struct m0_buf *key,
252  const struct m0_buf *val)
253 {
255 }
256 
257 M0_INTERNAL void
259 {
260  m0_format_header_pack(&map->em_header, &(struct m0_format_tag){
261  .ot_version = M0_BE_EMAP_FORMAT_VERSION,
262  .ot_type = M0_FORMAT_TYPE_BE_EMAP,
263  .ot_footer_offset = offsetof(struct m0_be_emap, em_footer)
264  });
266  m0_buf_init(&map->em_key_buf, &map->em_key, sizeof map->em_key);
267  m0_buf_init(&map->em_val_buf, &map->em_rec, sizeof map->em_rec);
268  emap_key_init(&map->em_key);
269  emap_rec_init(&map->em_rec);
270  m0_be_btree_init(&map->em_mapping, db, &be_emap_ops);
271  map->em_seg = db;
272  map->em_version = 0;
274 }
275 
276 M0_INTERNAL void m0_be_emap_fini(struct m0_be_emap *map)
277 {
278  map->em_version = 0;
279  m0_be_btree_fini(&map->em_mapping);
281 }
282 
283 M0_INTERNAL void m0_be_emap_create(struct m0_be_emap *map,
284  struct m0_be_tx *tx,
285  struct m0_be_op *op,
286  const struct m0_fid *fid)
287 {
288  M0_PRE(map->em_seg != NULL);
289 
291  M0_BE_OP_SYNC(local_op,
292  m0_be_btree_create(&map->em_mapping, tx, &local_op,
293  &M0_FID_TINIT('b',
295  fid->f_key)));
296  op->bo_u.u_emap.e_rc = 0;
297  m0_be_op_done(op);
298 }
299 
300 M0_INTERNAL void m0_be_emap_destroy(struct m0_be_emap *map,
301  struct m0_be_tx *tx,
302  struct m0_be_op *op)
303 {
305  op->bo_u.u_emap.e_rc = M0_BE_OP_SYNC_RET(
306  local_op,
307  m0_be_btree_destroy(&map->em_mapping, tx, &local_op),
308  bo_u.u_btree.t_rc);
309  m0_be_op_done(op);
310 }
311 
312 M0_INTERNAL struct m0_be_emap_seg *
314 {
315  return &it->ec_seg;
316 }
317 
318 M0_INTERNAL bool m0_be_emap_ext_is_last(const struct m0_ext *ext)
319 {
320  return ext->e_end == M0_BINDEX_MAX + 1;
321 }
322 
323 M0_INTERNAL bool m0_be_emap_ext_is_first(const struct m0_ext *ext)
324 {
325  return ext->e_start == 0;
326 }
327 
328 M0_INTERNAL struct m0_be_op *m0_be_emap_op(struct m0_be_emap_cursor *it)
329 {
330  return &it->ec_op;
331 }
332 
333 M0_INTERNAL int m0_be_emap_op_rc(const struct m0_be_emap_cursor *it)
334 {
335  return it->ec_op.bo_u.u_emap.e_rc;
336 }
337 
338 M0_INTERNAL
340 {
341  return map->em_seg->bs_domain;
342 }
343 
344 M0_INTERNAL void m0_be_emap_lookup(struct m0_be_emap *map,
345  const struct m0_uint128 *prefix,
347  struct m0_be_emap_cursor *it)
348 {
350 
356 
358 }
359 
360 M0_INTERNAL void m0_be_emap_close(struct m0_be_emap_cursor *it)
361 {
363  be_emap_close(it);
364 }
365 
367 {
368  if (it->ec_version != it->ec_map->em_version || M0_FI_ENABLED("yes")) {
369  M0_LOG(M0_DEBUG, "versions mismatch: %d != %d",
370  (int)it->ec_version, (int)it->ec_map->em_version);
372  return true;
373  } else
374  return false;
375 }
376 
377 M0_INTERNAL void m0_be_emap_next(struct m0_be_emap_cursor *it)
378 {
380 
382 
385  be_emap_next(it);
387 
389 }
390 
391 M0_INTERNAL void m0_be_emap_prev(struct m0_be_emap_cursor *it)
392 {
394 
396 
398  if (!be_emap_changed(it, it->ec_rec.er_start - 1))
399  be_emap_prev(it);
401 
403 }
404 
406  struct m0_be_tx *tx,
407  const struct m0_be_emap_seg *es)
408 {
410  emap_extent_update(it, tx, es);
412 }
413 
415  struct m0_be_tx *tx,
416  m0_bindex_t delta,
417  bool get_next)
418 {
419  int rc = 0;
420 
421  if (get_next)
422  rc = be_emap_next(it);
423 
424  if (rc == 0) {
425  it->ec_seg.ee_ext.e_start -= delta;
426  rc = emap_extent_update(it, tx, &it->ec_seg);
427  }
428 
429  return M0_RC(rc);
430 }
431 
432 M0_INTERNAL void m0_be_emap_merge(struct m0_be_emap_cursor *it,
433  struct m0_be_tx *tx,
434  m0_bindex_t delta)
435 {
436  bool inserted = false;
437  int rc;
438 
440  M0_PRE(delta <= m0_ext_length(&it->ec_seg.ee_ext));
442 
444 
447 
448  if (rc == 0 && delta < m0_ext_length(&it->ec_seg.ee_ext)) {
449  it->ec_seg.ee_ext.e_end -= delta;
451  inserted = true;
452  }
453 
454  if (rc == 0)
455  rc = emap_it_get(it) /* re-initialise cursor position */ ?:
456  update_next_segment(it, tx, delta, inserted);
458 
460  it->ec_op.bo_u.u_emap.e_rc = rc;
462 }
463 
464 M0_INTERNAL void m0_be_emap_split(struct m0_be_emap_cursor *it,
465  struct m0_be_tx *tx,
466  struct m0_indexvec *vec,
467  struct m0_buf *cksum)
468 {
471 
474  be_emap_split(it, tx, vec, it->ec_seg.ee_ext.e_start, cksum);
477 
479 }
480 
481 /* This function will paste the extent (ext) into all the existing overlapping
482  * extent. It is assumed that cursor is correctly placed so ext is part of
483  * cursor-segment (it->ec_seg).
484  *
485  * 1. Finds the overlap of current-segment with the new extent (ext)
486  * 2. Based on the overlap, atmost 3 sub-segment can get created
487  * (term left/right w.r.t area of current segment left after removing clip area)
488  * a. Left sub-seg : Overlap of start of cur-seg with ext
489  * | cur-seg |
490  * | clip - ext |
491  * |Left| => [curr-seg:Start - clip:Start]
492  * b. Middle sub-seg : If ext part (to be pasted) fully overlaps with curr-seg (clip)
493  * | cur-seg |
494  * | clip - ext |
495  * | Left | Middle | Right |
496  * c. Right sub-seg : Overalp of end of cur-seg with ext
497  * | cur-seg |
498  * | clip - ext |
499  * |Right | => [clip:End - curr-seg:End]
500  * 3. EMAP operation for these three segments are performed (not all may be needed)
501  * 4. If part of extent (after removing clip) is remaining then new segment is read
502  * (be_emap_next) and again above operations are performed
503  *
504  * For checksum operation :
505  * a. Left Opn : Reduce the checksum number of byte from checksum of left segment
506  * b. Right Opn : Update checksum new start and size
507  *
508  * During operation like punch, we need to find the size of single unit of checksum
509  * this is derived based on unit size (one checksum unit for one data unit) and total
510  * checksum size.
511  *
512  * COB when created has following extent: [0, infinity or -1 ), er_value: AET_HOLE
513  * so when x-DU (Data Units) gets pasted extents are:
514  * [0, x-DU), er_value: x-DeviceLBA
515  * [x-DU, infinity or -1 ), er_value: AET_HOLE
516  */
517 M0_INTERNAL void m0_be_emap_paste(struct m0_be_emap_cursor *it,
518  struct m0_be_tx *tx,
519  struct m0_ext *ext,
520  uint64_t val,
521  void (*del)(struct m0_be_emap_seg*),
522  void (*cut_left)(struct m0_be_emap_seg*, struct m0_ext*, uint64_t),
523  void (*cut_right)(struct m0_be_emap_seg*, struct m0_ext*, uint64_t))
524 {
525  struct m0_be_emap_seg *seg = &it->ec_seg;
526  struct m0_ext *chunk = &seg->ee_ext;
527  const struct m0_ext ext0 = *ext;
528  struct m0_ext clip;
529  m0_bcount_t length[3];
530  typeof(val) bstart[3] = {};
531  struct m0_buf cksum[3] = {{0, NULL},
532  {0, NULL},
533  {0, NULL}};
534  m0_bcount_t chunk_cs_count;
535  m0_bcount_t cksum_unit_size = 0;
536 
537  m0_bcount_t consumed;
538  uint64_t val_orig;
539  struct m0_indexvec vec = {
540  .iv_vec = {
541  .v_nr = ARRAY_SIZE(length),
542  .v_count = length
543  },
544  .iv_index = bstart
545  };
546  int rc = 0;
547 
548  M0_PRE(m0_ext_is_in(chunk, ext->e_start));
550 
552 
554 
555  /*
556  * Iterate over existing segments overlapping with the new one,
557  * calculating for each, what parts have to be deleted and what remains.
558  *
559  * In the worst case, an existing segment can split into three
560  * parts. Generally, some of these parts can be empty.
561  *
562  * Cutting and deleting segments is handled uniformly by
563  * be_emap_split(), thanks to the latter skipping empty segments.
564  *
565  * Note that the _whole_ new segment is inserted on the last iteration
566  * of the loop below (see length[1] assignment), thus violating the map
567  * invariant until the loop exits (the map is "porous" during that
568  * time).
569  */
571 
572  while (!m0_ext_is_empty(ext)) {
573  m0_ext_intersection(ext, chunk, &clip);
574  M0_LOG(M0_DEBUG, "ext="EXT_F" chunk="EXT_F" clip="EXT_F,
575  EXT_P(ext), EXT_P(chunk), EXT_P(&clip));
576  consumed = m0_ext_length(&clip);
577  M0_ASSERT(consumed > 0);
578 
579  length[0] = clip.e_start - chunk->e_start;
580  length[1] = clip.e_end == ext->e_end ? m0_ext_length(&ext0) : 0;
581  length[2] = chunk->e_end - clip.e_end;
582  M0_LOG(M0_DEBUG, "len123=%lx:%lx:%lx", (unsigned long)length[0],
583  (unsigned long)length[1], (unsigned long)length[2]);
584 
585  bstart[1] = val;
586  val_orig = seg->ee_val;
587  cksum[1] = it->ec_app_cksum_buf;
588 
589  if (seg->ee_cksum_buf.b_nob)
590  {
591  // Compute checksum unit size for given segment
592  chunk_cs_count = m0_extent_get_num_unit_start(chunk->e_start,
593  m0_ext_length(chunk),
594  it->ec_unit_size);
595  M0_ASSERT(chunk_cs_count);
596  cksum_unit_size = seg->ee_cksum_buf.b_nob/chunk_cs_count;
597  M0_ASSERT(cksum_unit_size);
598  }
599 
600  if (length[0] > 0) {
601  if (cut_left)
602  cut_left(seg, &clip, val_orig);
603  bstart[0] = seg->ee_val;
604  if (seg->ee_cksum_buf.b_nob) {
605  cksum[0].b_nob = m0_extent_get_checksum_nob(chunk->e_start,
606  length[0],
607  it->ec_unit_size,
608  cksum_unit_size);
609  cksum[0].b_addr = seg->ee_cksum_buf.b_addr;
610  }
611  }
612  if (length[2] > 0) {
613  if (cut_right)
614  cut_right(seg, &clip, val_orig);
615  bstart[2] = seg->ee_val;
616  if (seg->ee_cksum_buf.b_nob) {
617  cksum[2].b_nob = m0_extent_get_checksum_nob(clip.e_end, length[2],
618  it->ec_unit_size,
619  cksum_unit_size);
621  clip.e_end,
622  chunk->e_start,
623  it->ec_unit_size,
624  cksum_unit_size);
625  }
626  }
627  if (length[0] == 0 && length[2] == 0 && del)
628  del(seg);
629 
630  rc = be_emap_split(it, tx, &vec, length[0] > 0 ?
631  chunk->e_start : ext0.e_start,
632  cksum);
633  if (rc != 0)
634  break;
635 
636  ext->e_start += consumed;
637  M0_ASSERT(ext->e_start <= ext->e_end);
638 
639  M0_LOG(M0_DEBUG, "left %llu",
640  (unsigned long long)m0_ext_length(ext));
641 
642  if (m0_ext_is_empty(ext))
643  break;
644  /*
645  * If vec is empty, be_emap_split() just deletes
646  * the current extent and puts iterator to the next
647  * position automatically.
648  */
649  if (!m0_vec_is_empty(&vec.iv_vec)) {
651  if (be_emap_next(it) != 0)
652  break;
653  }
654  }
656 
657  /* emap_dump(it); */ /* expensive - use for debug only */
658 
660 
661  it->ec_op.bo_u.u_emap.e_rc = rc;
662 
664 
665  /*
666  * A tale of two keys.
667  *
668  * Primordial version of this function inserted the whole new extent (as
669  * specified by @ext) at the first iteration of the loop. From time to
670  * time the (clip.e_start == ext->e_start) assertion got violated for no
671  * apparent reason. Eventually, after a lot of tracing (by Anatoliy),
672  * the following sequence was tracked down:
673  *
674  * - on entry to m0_be_emap_paste():
675  *
676  * map: *[0, 512) [512, 1024) [1024, 2048) [2048, ...)
677  * ext: [0, 1024)
678  *
679  * (where current cursor position is starred).
680  *
681  * - at the end of the first iteration, instead of expected
682  *
683  * map: [0, 1024) *[512, 1024) [1024, 2048) [2048, ...)
684  *
685  * the map was
686  *
687  * map: [0, 1024) *[1024, 2048) [2048, ...)
688  *
689  * - that is, the call to be_emap_split():
690  *
691  * - deleted [0, 512) (as expected),
692  * - inserted [0, 1024) (as expected),
693  * - deleted [512, 1024) ?!
694  *
695  * The later is seemingly impossible, because the call deletes exactly
696  * one segment. The surprising explanation is that segment ([L, H), V)
697  * is stored as a record (L, V) with H as a key (this is documented at
698  * the top of this file) and the [0, 1024) segment has the same key as
699  * already existing [512, 1024) one, with the former forever masking the
700  * latter.
701  *
702  * The solution is to insert the new extent as the last step, but the
703  * more important moral of this melancholy story is
704  *
705  * Thou shalt wit thine abstraction levels.
706  *
707  * In the present case, be_emap_split() operates on the level of
708  * records and keys which turns out to be subtly different from the
709  * level of segments and maps.
710  */
711 }
712 
713 M0_INTERNAL int m0_be_emap_count(struct m0_be_emap_cursor *it,
714  m0_bcount_t *segs)
715 {
716  struct m0_be_emap_seg *seg;
717  struct m0_be_op *op;
718  m0_bcount_t nr_segs = 0;
719  int rc = 0;
720 
722 
723  op = m0_be_emap_op(it);
724  do {
728  ++nr_segs;
730  break;
731  M0_SET0(op);
732  m0_be_op_init(op);
734  m0_be_op_wait(op);
736  m0_be_op_fini(op);
737  } while (rc == 0);
738 
739  *segs = nr_segs;
740 
741  return M0_RC(rc);
742 }
743 
744 M0_INTERNAL void m0_be_emap_obj_insert(struct m0_be_emap *map,
745  struct m0_be_tx *tx,
746  struct m0_be_op *op,
747  const struct m0_uint128 *prefix,
748  uint64_t val)
749 {
751 
753  map->em_key.ek_prefix = *prefix;
754  map->em_key.ek_offset = M0_BINDEX_MAX + 1;
755  m0_format_footer_update(&map->em_key);
756  map->em_rec.er_start = 0;
757  map->em_rec.er_value = val;
758  map->em_rec.er_cksum_nob = 0;
759  emap_rec_init(&map->em_rec);
760 
761  ++map->em_version;
762  M0_LOG(M0_DEBUG, "Nob: key = %" PRIu64 " val = %" PRIu64 " ",
763  map->em_key_buf.b_nob, map->em_val_buf.b_nob );
764  op->bo_u.u_emap.e_rc = M0_BE_OP_SYNC_RET(
765  local_op,
766  m0_be_btree_insert(&map->em_mapping, tx, &local_op,
767  &map->em_key_buf, &map->em_val_buf),
768  bo_u.u_btree.t_rc);
770 
771  m0_be_op_done(op);
772 }
773 
774 M0_INTERNAL void m0_be_emap_obj_delete(struct m0_be_emap *map,
775  struct m0_be_tx *tx,
776  struct m0_be_op *op,
777  const struct m0_uint128 *prefix)
778 {
779  int rc = -ENOMEM;
780 #ifdef __KERNEL__
781  struct m0_be_emap_cursor *it;
782  M0_ALLOC_PTR(it);
783  if (it == NULL)
784  goto err;
785 #else
786  struct m0_be_emap_cursor it_s;
787  struct m0_be_emap_cursor *it = &it_s;
788 #endif
789 
790  /* Clear record buffer before lookup as it will use m0_buf for allocation
791  * and saving the variable size record having checksum
792  */
793  it->ec_recbuf.b_addr = NULL;
794  it->ec_recbuf.b_nob = 0;
795 
797 
799  rc = be_emap_lookup(map, prefix, 0, it);
800  if (rc == 0) {
804  be_emap_close(it);
805  }
807 
808 #ifdef __KERNEL__
809  m0_free(it);
810  err:
811 #endif
812  op->bo_u.u_emap.e_rc = rc;
813 
814  m0_be_op_done(op);
815 }
816 
817 M0_INTERNAL void m0_be_emap_caret_init(struct m0_be_emap_caret *car,
818  struct m0_be_emap_cursor *it,
820 {
823  car->ct_it = it;
824  car->ct_index = index;
826 }
827 
828 M0_INTERNAL void m0_be_emap_caret_fini(struct m0_be_emap_caret *car)
829 {
831 }
832 
833 M0_INTERNAL m0_bcount_t
835 {
837  return car->ct_it->ec_seg.ee_ext.e_end - car->ct_index;
838 }
839 
840 M0_INTERNAL int m0_be_emap_caret_move(struct m0_be_emap_caret *car,
842 {
843  int rc = 0;
844 
845  m0_be_op_active(&car->ct_it->ec_op);
846 
849  while (count > 0 && car->ct_index < M0_BINDEX_MAX + 1) {
850  m0_bcount_t step;
851 
852  step = m0_be_emap_caret_step(car);
853  if (count >= step) {
854  struct m0_be_emap_cursor *it = car->ct_it;
855  if (be_emap_changed(it, car->ct_index))
856  rc = it->ec_op.bo_u.u_emap.e_rc;
857  rc = rc ?: be_emap_next(it);
858  if (rc < 0)
859  break;
860  } else
861  step = count;
862  car->ct_index += step;
863  count -= step;
864  }
867 
868  m0_be_op_done(&car->ct_it->ec_op);
869  return rc < 0 ? rc : car->ct_index == M0_BINDEX_MAX + 1;
870 }
871 
872 M0_INTERNAL int m0_be_emap_caret_move_sync(struct m0_be_emap_caret *car,
874 {
875  int rc = 0;
876 
877  M0_SET0(&car->ct_it->ec_op);
878  m0_be_op_init(&car->ct_it->ec_op);
880  if (rc == 0)
881  m0_be_op_wait(&car->ct_it->ec_op);
882 
883  return rc;
884 }
885 
886 M0_INTERNAL void m0_be_emap_credit(struct m0_be_emap *map,
887  enum m0_be_emap_optype optype,
888  m0_bcount_t nr,
889  struct m0_be_tx_credit *accum)
890 {
891  uint64_t emap_rec_size;
892 
896 
897  /* emap rec static size + size of max checksum possible */
898  emap_rec_size = sizeof map->em_rec + max_cksum_size() * MAX_DUS;
899 
900  switch (optype) {
901  case M0_BEO_CREATE:
902  m0_be_btree_create_credit(&map->em_mapping, nr, accum);
903  break;
904  case M0_BEO_DESTROY:
905  M0_ASSERT(nr == 1);
906  m0_be_btree_destroy_credit(&map->em_mapping, accum);
907  break;
908  case M0_BEO_INSERT:
909  m0_be_btree_insert_credit(&map->em_mapping, nr,
910  sizeof map->em_key, emap_rec_size, accum);
911  break;
912  case M0_BEO_DELETE:
913  m0_be_btree_delete_credit(&map->em_mapping, nr,
914  sizeof map->em_key, emap_rec_size, accum);
915  break;
916  case M0_BEO_UPDATE:
917  m0_be_btree_update_credit(&map->em_mapping, nr,
918  emap_rec_size, accum);
919  break;
920  case M0_BEO_MERGE:
921  m0_be_btree_delete_credit(&map->em_mapping, nr,
922  sizeof map->em_key, emap_rec_size, accum);
923  m0_be_btree_insert_credit(&map->em_mapping, nr,
924  sizeof map->em_key, emap_rec_size, accum);
925  m0_be_btree_update_credit(&map->em_mapping, nr,
926  emap_rec_size, accum);
927  break;
928  case M0_BEO_SPLIT:
929  m0_be_btree_delete_credit(&map->em_mapping, 1,
930  sizeof map->em_key, emap_rec_size, accum);
931  m0_be_btree_insert_credit(&map->em_mapping, nr,
932  sizeof map->em_key, emap_rec_size, accum);
933  m0_be_btree_update_credit(&map->em_mapping, 1,
934  emap_rec_size, accum);
936  break;
937  case M0_BEO_PASTE:
939  true);
941  break;
942  default:
943  M0_IMPOSSIBLE("invalid emap operation");
944  }
945 }
946 
947 static int
948 be_emap_cmp(const void *key0, const void *key1)
949 {
950  const struct m0_be_emap_key *a0 = key0;
951  const struct m0_be_emap_key *a1 = key1;
952 
953  return m0_uint128_cmp(&a0->ek_prefix, &a1->ek_prefix) ?:
954  M0_3WAY(a0->ek_offset, a1->ek_offset);
955 }
956 
957 static m0_bcount_t
958 be_emap_ksize(const void* k)
959 {
960  return sizeof(struct m0_be_emap_key);
961 }
962 
963 static m0_bcount_t
964 be_emap_vsize(const void* d)
965 {
966  return sizeof(struct m0_be_emap_rec) +
967  ((struct m0_be_emap_rec *)d)->er_cksum_nob;
968 }
969 
970 static int
972  void (*btree_func)(struct m0_be_btree *btree,
973  struct m0_be_tx *tx,
974  struct m0_be_op *op,
975  const struct m0_buf *key,
976  const struct m0_buf *val),
977  struct m0_be_tx *tx)
978 {
979  const struct m0_be_emap_seg *ext = &it->ec_seg;
980  struct m0_be_emap_key *key = &it->ec_key;
981  struct m0_be_emap_rec *rec = &it->ec_rec;
982  struct m0_buf rec_buf = {};
983  struct m0_be_emap_rec *rec_buf_ptr;
984  int len, rc;
985 
986  key->ek_prefix = ext->ee_pre;
987  key->ek_offset = ext->ee_ext.e_end;
989  rec->er_start = ext->ee_ext.e_start;
990  rec->er_value = ext->ee_val;
991  rec->er_cksum_nob = ext->ee_cksum_buf.b_nob;
992  rec->er_unit_size = it->ec_unit_size;
993 
994  /* Layout/format of emap-record (if checksum is present) which gets
995  * written:
996  * - [Hdr| Balloc-Ext-Start| B-Ext-Value| CS-nob| CS-Array[...]| Ftr]
997  * It gets stored as contigious buffer, so allocating buffer
998  */
999 
1000  /* Total size of buffer needed for storing emap extent & assign */
1001  len = sizeof(struct m0_be_emap_rec) + rec->er_cksum_nob;
1002  if ((rc = m0_buf_alloc(&rec_buf, len)) != 0) {
1003  return rc;
1004  }
1005 
1006 
1007  /* Copy emap record till checksum buf start */
1008  rec_buf_ptr = (struct m0_be_emap_rec *)rec_buf.b_addr;
1009  *rec_buf_ptr = *rec;
1010 
1011  /* Copy checksum array into emap record */
1012  if (rec->er_cksum_nob ) {
1013  memcpy( (void *)&rec_buf_ptr->er_footer,
1014  ext->ee_cksum_buf.b_addr, rec->er_cksum_nob );
1015  }
1016 
1017  emap_rec_init(rec_buf_ptr);
1018 
1019  ++it->ec_map->em_version;
1021  op,
1022  btree_func(&it->ec_map->em_mapping, tx, &op, &it->ec_keybuf,
1023  &rec_buf),
1024  bo_u.u_btree.t_rc);
1025 
1026  m0_buf_free(&rec_buf);
1027 
1028  return it->ec_op.bo_u.u_emap.e_rc;
1029 }
1030 
1031 static bool emap_it_prefix_ok(const struct m0_be_emap_cursor *it)
1032 {
1033  return m0_uint128_eq(&it->ec_seg.ee_pre, &it->ec_prefix);
1034 }
1035 
1036 static int emap_it_open(struct m0_be_emap_cursor *it)
1037 {
1038  struct m0_be_emap_key *key;
1039  struct m0_be_emap_rec *rec;
1040  struct m0_buf keybuf;
1041  struct m0_buf recbuf;
1042  struct m0_be_emap_seg *ext = &it->ec_seg;
1043  struct m0_be_op *op = &it->ec_cursor.bc_op;
1044  int rc;
1045 
1047 
1048  rc = op->bo_u.u_btree.t_rc;
1049  if (rc == 0) {
1050  m0_be_btree_cursor_kv_get(&it->ec_cursor, &keybuf, &recbuf);
1051 
1052  /* Key operation */
1053  key = keybuf.b_addr;
1054  it->ec_key = *key;
1055 
1056  /* Record operation */
1057  if (it->ec_recbuf.b_addr != NULL) {
1059  }
1060 
1061  /* Layout/format of emap-record (if checksum is present) which gets
1062  * written:
1063  * - [Hdr| Balloc-Ext-Start| B-Ext-Value| CS-nob| CS-Array[...]| Ftr]
1064  * It gets stored as contigious buffer, so allocating buffer
1065  */
1066  rc = m0_buf_alloc(&it->ec_recbuf, recbuf.b_nob);
1067  if ( rc != 0)
1068  return rc;
1069 
1070  /* Copying record buffer and loading into it->ec_rec, note record
1071  * will have incorrect footer in case of b_nob, but it->ec_recbuf
1072  * will have all correct values.
1073  */
1074  memcpy(it->ec_recbuf.b_addr, recbuf.b_addr, recbuf.b_nob );
1075  rec = it->ec_recbuf.b_addr;
1076  it->ec_rec = *rec;
1077 
1078  ext->ee_pre = key->ek_prefix;
1079  ext->ee_ext.e_start = rec->er_start;
1080  ext->ee_ext.e_end = key->ek_offset;
1081  m0_ext_init(&ext->ee_ext);
1082  ext->ee_val = rec->er_value;
1083  ext->ee_cksum_buf.b_nob = rec->er_cksum_nob;
1084  ext->ee_cksum_buf.b_addr = rec->er_cksum_nob ?
1085  (void *)&rec->er_footer : NULL;
1086  it->ec_unit_size = rec->er_unit_size;
1087  if (!emap_it_prefix_ok(it))
1088  rc = -ESRCH;
1089  }
1090  it->ec_op.bo_u.u_emap.e_rc = rc;
1091 
1092  return rc;
1093 }
1094 
1095 static void emap_it_init(struct m0_be_emap_cursor *it,
1096  const struct m0_uint128 *prefix,
1098  struct m0_be_emap *map)
1099 {
1100  /* As EMAP record will now be variable we can't assign fix space */
1101  m0_buf_init(&it->ec_keybuf, &it->ec_key, sizeof it->ec_key);
1102 
1104  it->ec_key.ek_offset = offset + 1;
1105 
1106  it->ec_map = map;
1107  it->ec_version = map->em_version;
1108  m0_be_btree_cursor_init(&it->ec_cursor, &map->em_mapping);
1109 }
1110 
1111 static void be_emap_close(struct m0_be_emap_cursor *it)
1112 {
1113  if(it->ec_recbuf.b_addr != NULL ) {
1115  }
1116 
1118 }
1119 
1120 static int emap_it_get(struct m0_be_emap_cursor *it)
1121 {
1122  struct m0_be_op *op = &it->ec_cursor.bc_op;
1123  int rc;
1124 
1125  M0_SET0(op);
1126  m0_be_op_init(op);
1128  m0_be_op_wait(op);
1129  rc = emap_it_open(it);
1130  m0_be_op_fini(op);
1131 
1132  return rc;
1133 }
1134 
1135 static int be_emap_lookup(struct m0_be_emap *map,
1136  const struct m0_uint128 *prefix,
1138  struct m0_be_emap_cursor *it)
1139 {
1140  int rc;
1141 
1143  rc = emap_it_get(it);
1144  if (rc != 0)
1145  be_emap_close(it);
1146 
1148 
1149  return M0_RC(rc);
1150 }
1151 
1152 static int be_emap_next(struct m0_be_emap_cursor *it)
1153 {
1154  struct m0_be_op *op = &it->ec_cursor.bc_op;
1155  int rc;
1156 
1157  M0_SET0(op);
1158  m0_be_op_init(op);
1160  m0_be_op_wait(op);
1161  rc = emap_it_open(it);
1162  m0_be_op_fini(op);
1163 
1164  return rc;
1165 }
1166 
1167 static int
1169 {
1170  struct m0_be_op *op = &it->ec_cursor.bc_op;
1171  int rc;
1172 
1173  M0_SET0(op);
1174  m0_be_op_init(op);
1176  m0_be_op_wait(op);
1177  rc = emap_it_open(it);
1178  m0_be_op_fini(op);
1179 
1180  return rc;
1181 }
1182 
1183 #if 1
1184 static bool
1186 {
1187  int rc;
1188  m0_bindex_t reached = 0;
1189  m0_bcount_t total = 0;
1190 
1192  return false;
1193  while (1) {
1194  if (!_0C(it->ec_seg.ee_ext.e_start == reached))
1195  return false;
1196  if (!_0C(it->ec_seg.ee_ext.e_end > reached))
1197  return false;
1198  if (!_0C(m0_format_footer_verify(&it->ec_key, true) == 0))
1199  return false;
1200  if (!_0C(m0_format_footer_verify(it->ec_recbuf.b_addr, true) == 0))
1201  return false;
1202  reached = it->ec_seg.ee_ext.e_end;
1205  break;
1206  rc = be_emap_next(it);
1207  if (rc != 0)
1208  break;
1209  }
1210  if (!_0C(total == M0_BCOUNT_MAX))
1211  return false;
1212  if (!_0C(reached == M0_BINDEX_MAX + 1))
1213  return false;
1214  return true;
1215 }
1216 
1217 static bool
1219 {
1220  bool is_good = true;
1221  int rc;
1222 #ifdef __KERNEL__
1223  struct m0_be_emap_cursor *scan;
1224 
1225  M0_ALLOC_PTR(scan);
1226  if (scan == NULL)
1227  return false;
1228 #else
1229  struct m0_be_emap_cursor scan_s;
1230  struct m0_be_emap_cursor *scan = &scan_s;
1231 #endif
1232 
1233  scan->ec_recbuf.b_addr = NULL;
1234  scan->ec_recbuf.b_nob = 0;
1235 
1238  if (rc == 0) {
1239  is_good = be_emap_invariant_check(scan);
1241  }
1243 
1244  if (!is_good)
1245  emap_dump(it);
1246 
1247 #ifdef __KERNEL__
1248  m0_free(scan);
1249 #endif
1250 
1251  return is_good;
1252 }
1253 
1254 #else
1255 
1256 static bool
1258 {
1259  return true;
1260 }
1261 #endif
1262 
1263 static int
1265  struct m0_be_tx *tx,
1266  const struct m0_be_emap_seg *es)
1267 {
1268  M0_PRE(it != NULL);
1269  M0_PRE(es != NULL);
1271  M0_PRE(it->ec_seg.ee_ext.e_end == es->ee_ext.e_end);
1272 
1274  it->ec_seg.ee_val = es->ee_val;
1275  return emap_it_pack(it, m0_be_btree_update, tx);
1276 }
1277 
1278 static int
1280  struct m0_be_tx *tx,
1281  struct m0_indexvec *vec,
1282  m0_bindex_t scan,
1283  struct m0_buf *cksum)
1284 {
1285  int rc = 0;
1287  m0_bindex_t seg_end = it->ec_seg.ee_ext.e_end;
1288  uint32_t i;
1289 
1290  for (i = 0; i < vec->iv_vec.v_nr; ++i) {
1291  count = vec->iv_vec.v_count[i];
1292  if (count == 0)
1293  continue;
1296  it->ec_seg.ee_ext.e_end = scan + count;
1297  it->ec_seg.ee_val = vec->iv_index[i];
1298  it->ec_seg.ee_cksum_buf = cksum[i];
1299 
1300  if (it->ec_seg.ee_ext.e_end == seg_end)
1301  /* The end of original segment is reached:
1302  * just update it instead of deleting and
1303  * inserting again - it is cheaper.
1304  * Note: the segment key in underlying btree
1305  * is the end offset of its extent. */
1307  else
1309  if (rc != 0)
1310  break;
1311  scan += count;
1312  }
1313 
1314  /* If the vector is empty or the segment end was not reached:
1315  * just delete the segment - that is used by m0_be_emap_paste(). */
1316  if (rc == 0 && (m0_vec_is_empty(&vec->iv_vec) ||
1317  it->ec_seg.ee_ext.e_end != seg_end)) {
1318  m0_bindex_t last_end = it->ec_seg.ee_ext.e_end;
1319  it->ec_seg.ee_ext.e_end = seg_end;
1320  rc = emap_it_pack(it, delete_wrapper, tx);
1321  it->ec_key.ek_offset = last_end;
1323  }
1324 
1325  if (rc == 0)
1326  /* Re-initialize cursor position. */
1327  rc = emap_it_get(it);
1328 
1329  it->ec_op.bo_u.u_emap.e_rc = rc;
1330  return M0_RC(rc);
1331 }
1332 
1333 static bool
1335 {
1336  return _0C(m0_ext_is_in(&car->ct_it->ec_seg.ee_ext, car->ct_index) ||
1338  car->ct_index == M0_BINDEX_MAX + 1));
1339 }
1340 
1342 #undef M0_TRACE_SUBSYSTEM
1343 
1344 /*
1345  * Local variables:
1346  * c-indentation-style: "K&R"
1347  * c-basic-offset: 8
1348  * tab-width: 8
1349  * fill-column: 80
1350  * scroll-step: 1
1351  * End:
1352  */
M0_INTERNAL int m0_uint128_cmp(const struct m0_uint128 *u0, const struct m0_uint128 *u1)
Definition: misc.c:45
M0_INTERNAL struct m0_be_domain * m0_be_emap_seg_domain(const struct m0_be_emap *map)
Definition: extmap.c:339
struct m0_format_header er_header
m0_bindex_t ek_offset
static int emap_it_open(struct m0_be_emap_cursor *it)
Definition: extmap.c:1036
M0_INTERNAL void m0_be_btree_cursor_next(struct m0_be_btree_cursor *cur)
Definition: btree.c:2358
static size_t nr
Definition: dump.c:1505
#define M0_PRE(cond)
M0_INTERNAL void m0_be_btree_delete_credit(const struct m0_be_btree *tree, m0_bcount_t nr, m0_bcount_t ksize, m0_bcount_t vsize, struct m0_be_tx_credit *accum)
Definition: btree.c:1740
M0_INTERNAL m0_bcount_t m0_ext_length(const struct m0_ext *ext)
Definition: ext.c:42
static m0_bcount_t be_emap_ksize(const void *k)
Definition: extmap.c:958
M0_INTERNAL void m0_be_emap_next(struct m0_be_emap_cursor *it)
Definition: extmap.c:377
uint64_t ko_type
Definition: btree.h:97
M0_INTERNAL void m0_format_header_pack(struct m0_format_header *dest, const struct m0_format_tag *src)
Definition: format.c:40
m0_bindex_t e_end
Definition: ext.h:40
#define NULL
Definition: misc.h:38
M0_INTERNAL m0_bcount_t m0_be_emap_caret_step(const struct m0_be_emap_caret *car)
Definition: extmap.c:834
map
Definition: processor.c:112
static m0_bcount_t be_emap_vsize(const void *d)
Definition: extmap.c:964
Definition: idx_mock.c:52
#define ergo(a, b)
Definition: misc.h:293
#define M0_3WAY(v0, v1)
Definition: arith.h:199
union m0_be_rwlock::@198 bl_u
struct m0_be_rwlock em_lock
void * b_addr
Definition: buf.h:39
M0_INTERNAL int m0_be_emap_dump(struct m0_be_emap *map)
Definition: extmap.c:199
M0_INTERNAL bool m0_uint128_eq(const struct m0_uint128 *u0, const struct m0_uint128 *u1)
Definition: misc.c:39
#define M0_LOG(level,...)
Definition: trace.h:167
uint64_t ee_val
Definition: extmap.h:193
M0_INTERNAL int m0_be_emap_caret_move(struct m0_be_emap_caret *car, m0_bcount_t count)
Definition: extmap.c:840
struct m0_be_emap_key ec_key
Definition: extmap.h:209
static struct m0_uint128 prefix
Definition: extmap.c:45
#define M0_BE_OP_SYNC(op_obj, action)
Definition: op.h:190
struct m0_buf ec_keybuf
Definition: extmap.h:211
static m0_bcount_t segs[NR *IT]
Definition: vec.c:45
M0_INTERNAL void m0_buf_init(struct m0_buf *buf, void *data, uint32_t nob)
Definition: buf.c:37
M0_INTERNAL void m0_rwlock_write_lock(struct m0_rwlock *lock)
Definition: rwlock.c:42
M0_INTERNAL void m0_be_emap_destroy(struct m0_be_emap *map, struct m0_be_tx *tx, struct m0_be_op *op)
Definition: extmap.c:300
M0_INTERNAL void m0_be_emap_obj_insert(struct m0_be_emap *map, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_uint128 *prefix, uint64_t val)
Definition: extmap.c:744
static int emap_extent_update(struct m0_be_emap_cursor *it, struct m0_be_tx *tx, const struct m0_be_emap_seg *es)
Definition: extmap.c:1264
M0_INTERNAL void m0_be_emap_prev(struct m0_be_emap_cursor *it)
Definition: extmap.c:391
struct m0_rwlock rwlock
Definition: format.h:208
M0_INTERNAL void m0_be_emap_close(struct m0_be_emap_cursor *it)
Definition: extmap.c:360
static struct m0_be_emap_cursor it
Definition: extmap.c:46
struct m0_buf ec_recbuf
Definition: extmap.h:212
static int emap_it_pack(struct m0_be_emap_cursor *it, void(*btree_func)(struct m0_be_btree *btree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key, const struct m0_buf *val), struct m0_be_tx *tx)
Definition: extmap.c:971
uint64_t m0_bindex_t
Definition: types.h:80
static void emap_dump(struct m0_be_emap_cursor *it)
Definition: extmap.c:139
uint64_t m0_bcount_t
Definition: types.h:77
m0_bindex_t er_unit_size
static bool be_emap_invariant(struct m0_be_emap_cursor *it)
Definition: extmap.c:1218
m0_be_emap_optype
Definition: extmap.h:415
M0_INTERNAL void * m0_extent_get_checksum_addr(void *b_addr, m0_bindex_t off, m0_bindex_t base_off, m0_bindex_t unit_sz, m0_bcount_t cs_size)
Definition: cksum_utils.c:74
m0_bindex_t ec_unit_size
Definition: extmap.h:214
struct m0_be_emap_seg ec_seg
Definition: extmap.h:206
M0_INTERNAL void m0_be_btree_create(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_fid *btree_fid)
Definition: btree.c:1512
#define M0_SET0(obj)
Definition: misc.h:64
M0_INTERNAL m0_bcount_t m0_extent_get_checksum_nob(m0_bindex_t ext_start, m0_bindex_t ext_length, m0_bindex_t unit_sz, m0_bcount_t cs_size)
Definition: cksum_utils.c:85
M0_INTERNAL void m0_be_emap_split(struct m0_be_emap_cursor *it, struct m0_be_tx *tx, struct m0_indexvec *vec, struct m0_buf *cksum)
Definition: extmap.c:464
M0_INTERNAL void m0_be_btree_destroy_credit(struct m0_be_btree *tree, struct m0_be_tx_credit *accum)
Definition: btree.c:1831
M0_INTERNAL bool m0_be_emap_ext_is_first(const struct m0_ext *ext)
Definition: extmap.c:323
#define M0_BE_CREDIT_DEC(cr_user, tx)
Definition: tx.h:465
uint32_t er_cksum_nob
uint64_t ec_version
Definition: extmap.h:204
M0_INTERNAL void m0_be_emap_merge(struct m0_be_emap_cursor *it, struct m0_be_tx *tx, m0_bindex_t delta)
Definition: extmap.c:432
#define PRIx64
Definition: types.h:61
#define M0_INVARIANT_EX(cond)
static m0_bcount_t count
Definition: xcode.c:167
M0_INTERNAL void m0_be_btree_delete(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key)
Definition: btree.c:1958
M0_INTERNAL void m0_be_btree_cursor_fini(struct m0_be_btree_cursor *cursor)
Definition: btree.c:2290
M0_INTERNAL void m0_rwlock_init(struct m0_rwlock *lock)
Definition: rwlock.c:32
struct m0_buf ee_cksum_buf
Definition: extmap.h:194
M0_INTERNAL struct m0_be_op * m0_be_emap_op(struct m0_be_emap_cursor *it)
Definition: extmap.c:328
struct m0_fid fid
Definition: di.c:46
return M0_RC(rc)
op
Definition: libdemo.c:64
static int btree(struct scanner *s, struct rectype *r, char *buf)
Definition: beck.c:1270
#define M0_ASSERT_EX(cond)
Definition: buf.h:37
int i
Definition: dir.c:1033
#define PRIu64
Definition: types.h:58
M0_INTERNAL bool m0_vec_is_empty(const struct m0_vec *vec)
Definition: vec.c:58
uint64_t em_version
M0_INTERNAL bool m0_ext_is_valid(const struct m0_ext *ext)
Definition: ext.c:90
M0_INTERNAL int m0_be_emap_op_rc(const struct m0_be_emap_cursor *it)
Definition: extmap.c:333
static bool be_emap_invariant_check(struct m0_be_emap_cursor *it)
Definition: extmap.c:1185
return M0_ERR(-EOPNOTSUPP)
M0_INTERNAL void m0_be_emap_paste(struct m0_be_emap_cursor *it, struct m0_be_tx *tx, struct m0_ext *ext, uint64_t val, void(*del)(struct m0_be_emap_seg *), void(*cut_left)(struct m0_be_emap_seg *, struct m0_ext *, uint64_t), void(*cut_right)(struct m0_be_emap_seg *, struct m0_ext *, uint64_t))
Definition: extmap.c:517
M0_INTERNAL void m0_be_btree_update_credit(const struct m0_be_btree *tree, m0_bcount_t nr, m0_bcount_t vsize, struct m0_be_tx_credit *accum)
Definition: btree.c:1750
struct m0_be_btree_cursor ec_cursor
Definition: extmap.h:208
#define M0_BE_OP_SYNC_RET(op_obj, action, member)
Definition: op.h:243
m0_bindex_t ct_index
Definition: extmap.h:386
M0_INTERNAL void m0_be_emap_init(struct m0_be_emap *map, struct m0_be_seg *db)
Definition: extmap.c:258
static void del(void)
Definition: client_ut.c:3157
static int key
Definition: locality.c:283
M0_INTERNAL void m0_be_btree_create_credit(const struct m0_be_btree *tree, m0_bcount_t nr, struct m0_be_tx_credit *accum)
Definition: btree.c:1783
M0_INTERNAL void m0_be_btree_insert(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key, const struct m0_buf *val)
Definition: btree.c:1932
#define M0_FID_TINIT(type, container, key)
Definition: fid.h:90
if(value==NULL)
Definition: dir.c:350
M0_INTERNAL void m0_be_btree_insert_credit(const struct m0_be_btree *tree, m0_bcount_t nr, m0_bcount_t ksize, m0_bcount_t vsize, struct m0_be_tx_credit *accum)
Definition: btree.c:1720
static void * vec
Definition: xcode.c:168
m0_bcount_t b_nob
Definition: buf.h:38
struct m0_be_emap * ec_map
Definition: extmap.h:202
#define M0_ASSERT(cond)
M0_INTERNAL void m0_be_btree_destroy(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op)
Definition: btree.c:1538
M0_INTERNAL void m0_ext_init(struct m0_ext *ext)
Definition: ext.c:32
#define U128_P(x)
Definition: types.h:45
struct m0_uint128 ek_prefix
M0_INTERNAL void m0_be_emap_caret_init(struct m0_be_emap_caret *car, struct m0_be_emap_cursor *it, m0_bindex_t index)
Definition: extmap.c:817
struct m0_be_emap_rec ec_rec
Definition: extmap.h:210
static int key0
Definition: locality.c:282
M0_INTERNAL bool m0_be_emap_ext_is_last(const struct m0_ext *ext)
Definition: extmap.c:318
M0_INTERNAL void m0_be_emap_extent_update(struct m0_be_emap_cursor *it, struct m0_be_tx *tx, const struct m0_be_emap_seg *es)
Definition: extmap.c:405
struct m0_be_op ec_op
Definition: extmap.h:217
static void delete_wrapper(struct m0_be_btree *btree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key, const struct m0_buf *val)
Definition: extmap.c:250
struct m0_uint128 ee_pre
Definition: extmap.h:189
uint64_t u_hi
Definition: types.h:36
M0_INTERNAL int m0_buf_alloc(struct m0_buf *buf, size_t size)
Definition: buf.c:43
struct m0_be_op::@39::@40 u_emap
M0_INTERNAL void m0_be_btree_fini(struct m0_be_btree *tree)
Definition: btree.c:1503
#define M0_POST(cond)
M0_INTERNAL void m0_be_emap_fini(struct m0_be_emap *map)
Definition: extmap.c:276
M0_INTERNAL void m0_be_emap_lookup(struct m0_be_emap *map, const struct m0_uint128 *prefix, m0_bindex_t offset, struct m0_be_emap_cursor *it)
Definition: extmap.c:344
static int be_emap_next(struct m0_be_emap_cursor *it)
Definition: extmap.c:1152
M0_INTERNAL void m0_be_op_done(struct m0_be_op *op)
Definition: stubs.c:104
static m0_bindex_t offset
Definition: dump.c:173
M0_INTERNAL void m0_rwlock_write_unlock(struct m0_rwlock *lock)
Definition: rwlock.c:47
M0_INTERNAL void m0_be_emap_obj_delete(struct m0_be_emap *map, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_uint128 *prefix)
Definition: extmap.c:774
M0_INTERNAL void m0_buf_free(struct m0_buf *buf)
Definition: buf.c:55
Definition: seg.h:66
M0_INTERNAL bool m0_ext_is_in(const struct m0_ext *ext, m0_bindex_t index)
Definition: ext.c:48
struct m0_uint128 ec_prefix
Definition: extmap.h:213
M0_INTERNAL int m0_format_footer_verify(const void *buffer, bool iem)
Definition: format.c:149
#define EXT_P(x)
Definition: ext.h:86
M0_INTERNAL m0_bcount_t m0_vec_count(const struct m0_vec *vec)
Definition: vec.c:53
M0_INTERNAL bool m0_ext_is_empty(const struct m0_ext *ext)
Definition: ext.c:76
static int be_emap_split(struct m0_be_emap_cursor *it, struct m0_be_tx *tx, struct m0_indexvec *vec, m0_bindex_t scan, struct m0_buf *cksum)
Definition: extmap.c:1279
M0_INTERNAL m0_bcount_t m0_extent_get_num_unit_start(m0_bindex_t ext_start, m0_bindex_t ext_len, m0_bindex_t unit_sz)
Definition: cksum_utils.c:29
static struct m0_be_emap * emap
Definition: extmap.c:44
uint32_t er_cksum_nob
M0_INTERNAL void m0_be_btree_cursor_kv_get(struct m0_be_btree_cursor *cur, struct m0_buf *key, struct m0_buf *val)
Definition: btree.c:2485
static void emap_it_init(struct m0_be_emap_cursor *it, const struct m0_uint128 *prefix, m0_bindex_t offset, struct m0_be_emap *map)
Definition: extmap.c:1095
struct m0_be_btree em_mapping
struct m0_be_emap_cursor * ct_it
Definition: extmap.h:385
static bool emap_it_prefix_ok(const struct m0_be_emap_cursor *it)
Definition: extmap.c:1031
#define U128X_F
Definition: types.h:42
#define m0_forall(var, nr,...)
Definition: misc.h:112
struct m0_ext ee_ext
Definition: extmap.h:191
M0_INTERNAL void m0_be_btree_update(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key, const struct m0_buf *val)
Definition: btree.c:1941
static bool be_emap_changed(struct m0_be_emap_cursor *it, m0_bindex_t off)
Definition: extmap.c:366
static int be_emap_prev(struct m0_be_emap_cursor *it)
Definition: extmap.c:1168
#define EXT_F
Definition: ext.h:85
M0_INTERNAL void m0_be_op_active(struct m0_be_op *op)
Definition: stubs.c:100
M0_INTERNAL uint64_t max_cksum_size(void)
Definition: cksum.c:162
static bool be_emap_caret_invariant(const struct m0_be_emap_caret *car)
Definition: extmap.c:1334
#define M0_FI_ENABLED(tag)
Definition: finject.h:231
Definition: ext.h:37
Definition: fid.h:38
static int be_emap_lookup(struct m0_be_emap *map, const struct m0_uint128 *prefix, m0_bindex_t offset, struct m0_be_emap_cursor *it)
Definition: extmap.c:1135
uint64_t f_key
Definition: fid.h:40
m0_bindex_t e_start
Definition: ext.h:39
M0_INTERNAL void m0_format_footer_update(const void *buffer)
Definition: format.c:95
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
M0_INTERNAL void m0_be_btree_cursor_get(struct m0_be_btree_cursor *cur, const struct m0_buf *key, bool slant)
Definition: btree.c:2295
M0_INTERNAL void m0_be_btree_cursor_prev(struct m0_be_btree_cursor *cur)
Definition: btree.c:2411
#define MAX_DUS
Definition: extmap.c:38
static struct m0_be_emap_seg * seg
Definition: extmap.c:47
struct m0_be_op bc_op
Definition: btree.h:589
#define _0C(exp)
Definition: assert.h:311
M0_INTERNAL void m0_be_op_fini(struct m0_be_op *op)
Definition: stubs.c:92
M0_INTERNAL void m0_rwlock_read_lock(struct m0_rwlock *lock)
Definition: rwlock.c:52
M0_INTERNAL int m0_be_emap_caret_move_sync(struct m0_be_emap_caret *car, m0_bcount_t count)
Definition: extmap.c:872
M0_INTERNAL void m0_rwlock_fini(struct m0_rwlock *lock)
Definition: rwlock.c:37
M0_INTERNAL void m0_be_btree_init(struct m0_be_btree *tree, struct m0_be_seg *seg, const struct m0_be_btree_kv_ops *ops)
Definition: btree.c:1487
static const struct m0_be_btree_kv_ops be_emap_ops
Definition: extmap.c:127
static struct m0_rwlock * emap_rwlock(struct m0_be_emap *emap)
Definition: extmap.c:134
static void emap_key_init(struct m0_be_emap_key *key)
Definition: extmap.c:174
M0_INTERNAL void m0_be_btree_cursor_init(struct m0_be_btree_cursor *cur, struct m0_be_btree *btree)
Definition: btree.c:2281
#define M0_UINT128(hi, lo)
Definition: types.h:40
union m0_be_op::@39 bo_u
M0_INTERNAL void m0_ext_intersection(const struct m0_ext *e0, const struct m0_ext *e1, struct m0_ext *result)
Definition: ext.c:81
M0_INTERNAL void m0_rwlock_read_unlock(struct m0_rwlock *lock)
Definition: rwlock.c:57
static int total
Definition: base.c:302
M0_INTERNAL void m0_be_emap_credit(struct m0_be_emap *map, enum m0_be_emap_optype optype, m0_bcount_t nr, struct m0_be_tx_credit *accum)
Definition: extmap.c:886
struct m0_buf ec_app_cksum_buf
Definition: extmap.h:216
M0_INTERNAL int m0_be_emap_count(struct m0_be_emap_cursor *it, m0_bcount_t *segs)
Definition: extmap.c:713
static int update_next_segment(struct m0_be_emap_cursor *it, struct m0_be_tx *tx, m0_bindex_t delta, bool get_next)
Definition: extmap.c:414
struct m0_format_footer er_footer
m0_bindex_t er_start
Definition: op.h:74
static int emap_it_get(struct m0_be_emap_cursor *it)
Definition: extmap.c:1120
static int scan(struct scanner *s)
Definition: beck.c:963
M0_INTERNAL void m0_be_op_init(struct m0_be_op *op)
Definition: stubs.c:87
void m0_free(void *data)
Definition: memory.c:146
#define M0_BE_CREDIT_INC(n, cr_user, credit)
Definition: tx.h:464
int32_t rc
Definition: trigger_fop.h:47
M0_INTERNAL bool m0_be_op_is_done(struct m0_be_op *op)
Definition: stubs.c:108
#define ARRAY_SIZE(a)
Definition: misc.h:45
M0_INTERNAL void m0_be_emap_create(struct m0_be_emap *map, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_fid *fid)
Definition: extmap.c:283
static int be_emap_cmp(const void *key0, const void *key1)
Definition: extmap.c:948
M0_INTERNAL void m0_be_op_wait(struct m0_be_op *op)
Definition: stubs.c:96
M0_INTERNAL struct m0_be_emap_seg * m0_be_emap_seg_get(struct m0_be_emap_cursor *it)
Definition: extmap.c:313
static void emap_rec_init(struct m0_be_emap_rec *rec)
Definition: extmap.c:184
Definition: tx.h:280
Definition: idx_mock.c:47
M0_INTERNAL void m0_be_emap_caret_fini(struct m0_be_emap_caret *car)
Definition: extmap.c:828
#define M0_IMPOSSIBLE(fmt,...)
static void be_emap_close(struct m0_be_emap_cursor *it)
Definition: extmap.c:1111