]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librados_test_stub/TestMemIoCtxImpl.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / test / librados_test_stub / TestMemIoCtxImpl.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "test/librados_test_stub/TestMemIoCtxImpl.h"
5 #include "test/librados_test_stub/TestMemRadosClient.h"
6 #include "common/Clock.h"
7 #include "common/RWLock.h"
8 #include "include/err.h"
9 #include <boost/algorithm/string/predicate.hpp>
10 #include <boost/bind.hpp>
11 #include <errno.h>
12 #include <include/compat.h>
13
14 static void to_vector(const interval_set<uint64_t> &set,
15 std::vector<std::pair<uint64_t, uint64_t> > *vec) {
16 vec->clear();
17 for (interval_set<uint64_t>::const_iterator it = set.begin();
18 it != set.end(); ++it) {
19 vec->push_back(*it);
20 }
21 }
22
23 // see PrimaryLogPG::finish_extent_cmp()
24 static int cmpext_compare(const bufferlist &bl, const bufferlist &read_bl) {
25 for (uint64_t idx = 0; idx < bl.length(); ++idx) {
26 char read_byte = (idx < read_bl.length() ? read_bl[idx] : 0);
27 if (bl[idx] != read_byte) {
28 return -MAX_ERRNO - idx;
29 }
30 }
31 return 0;
32 }
33
34 namespace librados {
35
36 TestMemIoCtxImpl::TestMemIoCtxImpl() {
37 }
38
39 TestMemIoCtxImpl::TestMemIoCtxImpl(const TestMemIoCtxImpl& rhs)
40 : TestIoCtxImpl(rhs), m_client(rhs.m_client), m_pool(rhs.m_pool) {
41 m_pool->get();
42 }
43
44 TestMemIoCtxImpl::TestMemIoCtxImpl(TestMemRadosClient *client, int64_t pool_id,
45 const std::string& pool_name,
46 TestMemCluster::Pool *pool)
47 : TestIoCtxImpl(client, pool_id, pool_name), m_client(client),
48 m_pool(pool) {
49 m_pool->get();
50 }
51
52 TestMemIoCtxImpl::~TestMemIoCtxImpl() {
53 m_pool->put();
54 }
55
56 TestIoCtxImpl *TestMemIoCtxImpl::clone() {
57 return new TestMemIoCtxImpl(*this);
58 }
59
60 int TestMemIoCtxImpl::aio_remove(const std::string& oid, AioCompletionImpl *c, int flags) {
61 m_client->add_aio_operation(oid, true,
62 boost::bind(&TestMemIoCtxImpl::remove, this, oid,
63 get_snap_context()),
64 c);
65 return 0;
66 }
67
68 int TestMemIoCtxImpl::append(const std::string& oid, const bufferlist &bl,
69 const SnapContext &snapc) {
70 if (get_snap_read() != CEPH_NOSNAP) {
71 return -EROFS;
72 } else if (m_client->is_blacklisted()) {
73 return -EBLACKLISTED;
74 }
75
76 TestMemCluster::SharedFile file;
77 {
78 RWLock::WLocker l(m_pool->file_lock);
79 file = get_file(oid, true, snapc);
80 }
81
82 RWLock::WLocker l(file->lock);
83 auto off = file->data.length();
84 ensure_minimum_length(off + bl.length(), &file->data);
85 file->data.copy_in(off, bl.length(), bl);
86 return 0;
87 }
88
89 int TestMemIoCtxImpl::assert_exists(const std::string &oid) {
90 if (m_client->is_blacklisted()) {
91 return -EBLACKLISTED;
92 }
93
94 RWLock::RLocker l(m_pool->file_lock);
95 TestMemCluster::SharedFile file = get_file(oid, false, get_snap_context());
96 if (file == NULL) {
97 return -ENOENT;
98 }
99 return 0;
100 }
101
102 int TestMemIoCtxImpl::create(const std::string& oid, bool exclusive) {
103 if (get_snap_read() != CEPH_NOSNAP) {
104 return -EROFS;
105 } else if (m_client->is_blacklisted()) {
106 return -EBLACKLISTED;
107 }
108
109 RWLock::WLocker l(m_pool->file_lock);
110 get_file(oid, true, get_snap_context());
111 return 0;
112 }
113
114 int TestMemIoCtxImpl::list_snaps(const std::string& oid, snap_set_t *out_snaps) {
115 if (m_client->is_blacklisted()) {
116 return -EBLACKLISTED;
117 }
118
119 out_snaps->seq = 0;
120 out_snaps->clones.clear();
121
122 RWLock::RLocker l(m_pool->file_lock);
123 TestMemCluster::Files::iterator it = m_pool->files.find(
124 {get_namespace(), oid});
125 if (it == m_pool->files.end()) {
126 return -ENOENT;
127 }
128
129 bool include_head = false;
130 TestMemCluster::FileSnapshots &file_snaps = it->second;
131 for (TestMemCluster::FileSnapshots::iterator s_it = file_snaps.begin();
132 s_it != file_snaps.end(); ++s_it) {
133 TestMemCluster::File &file = *s_it->get();
134
135 if (file_snaps.size() > 1) {
136 out_snaps->seq = file.snap_id;
137 TestMemCluster::FileSnapshots::iterator next_it(s_it);
138 ++next_it;
139 if (next_it == file_snaps.end()) {
140 include_head = true;
141 break;
142 }
143
144 ++out_snaps->seq;
145 if (!file.exists) {
146 continue;
147 }
148
149 // update the overlap with the next version's overlap metadata
150 TestMemCluster::File &next_file = *next_it->get();
151 interval_set<uint64_t> overlap;
152 if (next_file.exists) {
153 overlap = next_file.snap_overlap;
154 }
155
156 clone_info_t clone;
157 clone.cloneid = file.snap_id;
158 clone.snaps = file.snaps;
159 to_vector(overlap, &clone.overlap);
160 clone.size = file.data.length();
161 out_snaps->clones.push_back(clone);
162 }
163 }
164
165 if ((file_snaps.size() == 1 && file_snaps.back()->data.length() > 0) ||
166 include_head)
167 {
168 // Include the SNAP_HEAD
169 TestMemCluster::File &file = *file_snaps.back();
170 if (file.exists) {
171 RWLock::RLocker l2(file.lock);
172 if (out_snaps->seq == 0 && !include_head) {
173 out_snaps->seq = file.snap_id;
174 }
175 clone_info_t head_clone;
176 head_clone.cloneid = librados::SNAP_HEAD;
177 head_clone.size = file.data.length();
178 out_snaps->clones.push_back(head_clone);
179 }
180 }
181 return 0;
182
183 }
184
185 int TestMemIoCtxImpl::omap_get_vals2(const std::string& oid,
186 const std::string& start_after,
187 const std::string &filter_prefix,
188 uint64_t max_return,
189 std::map<std::string, bufferlist> *out_vals,
190 bool *pmore) {
191 if (out_vals == NULL) {
192 return -EINVAL;
193 } else if (m_client->is_blacklisted()) {
194 return -EBLACKLISTED;
195 }
196
197 TestMemCluster::SharedFile file;
198 {
199 RWLock::RLocker l(m_pool->file_lock);
200 file = get_file(oid, false, get_snap_context());
201 if (file == NULL) {
202 return -ENOENT;
203 }
204 }
205
206 out_vals->clear();
207
208 RWLock::RLocker l(file->lock);
209 TestMemCluster::FileOMaps::iterator o_it = m_pool->file_omaps.find(
210 {get_namespace(), oid});
211 if (o_it == m_pool->file_omaps.end()) {
212 if (pmore) {
213 *pmore = false;
214 }
215 return 0;
216 }
217
218 TestMemCluster::OMap &omap = o_it->second;
219 TestMemCluster::OMap::iterator it = omap.begin();
220 if (!start_after.empty()) {
221 it = omap.upper_bound(start_after);
222 }
223
224 while (it != omap.end() && max_return > 0) {
225 if (filter_prefix.empty() ||
226 boost::algorithm::starts_with(it->first, filter_prefix)) {
227 (*out_vals)[it->first] = it->second;
228 --max_return;
229 }
230 ++it;
231 }
232 if (pmore) {
233 *pmore = (it != omap.end());
234 }
235 return 0;
236 }
237
238 int TestMemIoCtxImpl::omap_get_vals(const std::string& oid,
239 const std::string& start_after,
240 const std::string &filter_prefix,
241 uint64_t max_return,
242 std::map<std::string, bufferlist> *out_vals) {
243 return omap_get_vals2(oid, start_after, filter_prefix, max_return, out_vals, nullptr);
244 }
245
246 int TestMemIoCtxImpl::omap_rm_keys(const std::string& oid,
247 const std::set<std::string>& keys) {
248 if (get_snap_read() != CEPH_NOSNAP) {
249 return -EROFS;
250 } else if (m_client->is_blacklisted()) {
251 return -EBLACKLISTED;
252 }
253
254 TestMemCluster::SharedFile file;
255 {
256 RWLock::WLocker l(m_pool->file_lock);
257 file = get_file(oid, true, get_snap_context());
258 if (file == NULL) {
259 return -ENOENT;
260 }
261 }
262
263 RWLock::WLocker l(file->lock);
264 for (std::set<std::string>::iterator it = keys.begin();
265 it != keys.end(); ++it) {
266 m_pool->file_omaps[{get_namespace(), oid}].erase(*it);
267 }
268 return 0;
269 }
270
271 int TestMemIoCtxImpl::omap_set(const std::string& oid,
272 const std::map<std::string, bufferlist> &map) {
273 if (get_snap_read() != CEPH_NOSNAP) {
274 return -EROFS;
275 } else if (m_client->is_blacklisted()) {
276 return -EBLACKLISTED;
277 }
278
279 TestMemCluster::SharedFile file;
280 {
281 RWLock::WLocker l(m_pool->file_lock);
282 file = get_file(oid, true, get_snap_context());
283 if (file == NULL) {
284 return -ENOENT;
285 }
286 }
287
288 RWLock::WLocker l(file->lock);
289 for (std::map<std::string, bufferlist>::const_iterator it = map.begin();
290 it != map.end(); ++it) {
291 bufferlist bl;
292 bl.append(it->second);
293 m_pool->file_omaps[{get_namespace(), oid}][it->first] = bl;
294 }
295
296 return 0;
297 }
298
299 int TestMemIoCtxImpl::read(const std::string& oid, size_t len, uint64_t off,
300 bufferlist *bl) {
301 if (m_client->is_blacklisted()) {
302 return -EBLACKLISTED;
303 }
304
305 TestMemCluster::SharedFile file;
306 {
307 RWLock::RLocker l(m_pool->file_lock);
308 file = get_file(oid, false, get_snap_context());
309 if (file == NULL) {
310 return -ENOENT;
311 }
312 }
313
314 RWLock::RLocker l(file->lock);
315 if (len == 0) {
316 len = file->data.length();
317 }
318 len = clip_io(off, len, file->data.length());
319 if (bl != NULL && len > 0) {
320 bufferlist bit;
321 bit.substr_of(file->data, off, len);
322 append_clone(bit, bl);
323 }
324 return len;
325 }
326
327 int TestMemIoCtxImpl::remove(const std::string& oid, const SnapContext &snapc) {
328 if (get_snap_read() != CEPH_NOSNAP) {
329 return -EROFS;
330 } else if (m_client->is_blacklisted()) {
331 return -EBLACKLISTED;
332 }
333
334 RWLock::WLocker l(m_pool->file_lock);
335 TestMemCluster::SharedFile file = get_file(oid, false, snapc);
336 if (file == NULL) {
337 return -ENOENT;
338 }
339 file = get_file(oid, true, snapc);
340
341 {
342 RWLock::WLocker l2(file->lock);
343 file->exists = false;
344 }
345
346 TestCluster::ObjectLocator locator(get_namespace(), oid);
347 TestMemCluster::Files::iterator it = m_pool->files.find(locator);
348 ceph_assert(it != m_pool->files.end());
349
350 if (*it->second.rbegin() == file) {
351 TestMemCluster::ObjectHandlers object_handlers;
352 std::swap(object_handlers, m_pool->file_handlers[locator]);
353 m_pool->file_handlers.erase(locator);
354
355 for (auto object_handler : object_handlers) {
356 object_handler->handle_removed(m_client);
357 }
358 }
359
360 if (it->second.size() == 1) {
361 m_pool->files.erase(it);
362 m_pool->file_omaps.erase(locator);
363 }
364 return 0;
365 }
366
367 int TestMemIoCtxImpl::selfmanaged_snap_create(uint64_t *snapid) {
368 if (m_client->is_blacklisted()) {
369 return -EBLACKLISTED;
370 }
371
372 RWLock::WLocker l(m_pool->file_lock);
373 *snapid = ++m_pool->snap_id;
374 m_pool->snap_seqs.insert(*snapid);
375 return 0;
376 }
377
378 int TestMemIoCtxImpl::selfmanaged_snap_remove(uint64_t snapid) {
379 if (m_client->is_blacklisted()) {
380 return -EBLACKLISTED;
381 }
382
383 RWLock::WLocker l(m_pool->file_lock);
384 TestMemCluster::SnapSeqs::iterator it =
385 m_pool->snap_seqs.find(snapid);
386 if (it == m_pool->snap_seqs.end()) {
387 return -ENOENT;
388 }
389
390 // TODO clean up all file snapshots
391 m_pool->snap_seqs.erase(it);
392 return 0;
393 }
394
395 int TestMemIoCtxImpl::selfmanaged_snap_rollback(const std::string& oid,
396 uint64_t snapid) {
397 if (m_client->is_blacklisted()) {
398 return -EBLACKLISTED;
399 }
400
401 RWLock::WLocker l(m_pool->file_lock);
402
403 TestMemCluster::SharedFile file;
404 TestMemCluster::Files::iterator f_it = m_pool->files.find(
405 {get_namespace(), oid});
406 if (f_it == m_pool->files.end()) {
407 return 0;
408 }
409
410 TestMemCluster::FileSnapshots &snaps = f_it->second;
411 file = snaps.back();
412
413 size_t versions = 0;
414 for (TestMemCluster::FileSnapshots::reverse_iterator it = snaps.rbegin();
415 it != snaps.rend(); ++it) {
416 TestMemCluster::SharedFile file = *it;
417 if (file->snap_id < get_snap_read()) {
418 if (versions == 0) {
419 // already at the snapshot version
420 return 0;
421 } else if (file->snap_id == CEPH_NOSNAP) {
422 if (versions == 1) {
423 // delete it current HEAD, next one is correct version
424 snaps.erase(it.base());
425 } else {
426 // overwrite contents of current HEAD
427 file = TestMemCluster::SharedFile (new TestMemCluster::File(**it));
428 file->snap_id = CEPH_NOSNAP;
429 *it = file;
430 }
431 } else {
432 // create new head version
433 file = TestMemCluster::SharedFile (new TestMemCluster::File(**it));
434 file->snap_id = m_pool->snap_id;
435 snaps.push_back(file);
436 }
437 return 0;
438 }
439 ++versions;
440 }
441 return 0;
442 }
443
444 int TestMemIoCtxImpl::set_alloc_hint(const std::string& oid,
445 uint64_t expected_object_size,
446 uint64_t expected_write_size,
447 const SnapContext &snapc) {
448 if (get_snap_read() != CEPH_NOSNAP) {
449 return -EROFS;
450 } else if (m_client->is_blacklisted()) {
451 return -EBLACKLISTED;
452 }
453
454 {
455 RWLock::WLocker l(m_pool->file_lock);
456 get_file(oid, true, snapc);
457 }
458
459 return 0;
460 }
461
462 int TestMemIoCtxImpl::sparse_read(const std::string& oid, uint64_t off,
463 uint64_t len,
464 std::map<uint64_t,uint64_t> *m,
465 bufferlist *data_bl) {
466 if (m_client->is_blacklisted()) {
467 return -EBLACKLISTED;
468 }
469
470 // TODO verify correctness
471 TestMemCluster::SharedFile file;
472 {
473 RWLock::RLocker l(m_pool->file_lock);
474 file = get_file(oid, false, get_snap_context());
475 if (file == NULL) {
476 return -ENOENT;
477 }
478 }
479
480 RWLock::RLocker l(file->lock);
481 len = clip_io(off, len, file->data.length());
482 // TODO support sparse read
483 if (m != NULL) {
484 m->clear();
485 if (len > 0) {
486 (*m)[off] = len;
487 }
488 }
489 if (data_bl != NULL && len > 0) {
490 bufferlist bit;
491 bit.substr_of(file->data, off, len);
492 append_clone(bit, data_bl);
493 }
494 return len > 0 ? 1 : 0;
495 }
496
497 int TestMemIoCtxImpl::stat(const std::string& oid, uint64_t *psize,
498 time_t *pmtime) {
499 if (m_client->is_blacklisted()) {
500 return -EBLACKLISTED;
501 }
502
503 TestMemCluster::SharedFile file;
504 {
505 RWLock::RLocker l(m_pool->file_lock);
506 file = get_file(oid, false, get_snap_context());
507 if (file == NULL) {
508 return -ENOENT;
509 }
510 }
511
512 RWLock::RLocker l(file->lock);
513 if (psize != NULL) {
514 *psize = file->data.length();
515 }
516 if (pmtime != NULL) {
517 *pmtime = file->mtime;
518 }
519 return 0;
520 }
521
522 int TestMemIoCtxImpl::truncate(const std::string& oid, uint64_t size,
523 const SnapContext &snapc) {
524 if (get_snap_read() != CEPH_NOSNAP) {
525 return -EROFS;
526 } else if (m_client->is_blacklisted()) {
527 return -EBLACKLISTED;
528 }
529
530 TestMemCluster::SharedFile file;
531 {
532 RWLock::WLocker l(m_pool->file_lock);
533 file = get_file(oid, true, snapc);
534 }
535
536 RWLock::WLocker l(file->lock);
537 bufferlist bl(size);
538
539 interval_set<uint64_t> is;
540 if (file->data.length() > size) {
541 is.insert(size, file->data.length() - size);
542
543 bl.substr_of(file->data, 0, size);
544 file->data.swap(bl);
545 } else if (file->data.length() != size) {
546 if (size == 0) {
547 bl.clear();
548 } else {
549 is.insert(0, size);
550
551 bl.append_zero(size - file->data.length());
552 file->data.append(bl);
553 }
554 }
555 is.intersection_of(file->snap_overlap);
556 file->snap_overlap.subtract(is);
557 return 0;
558 }
559
560 int TestMemIoCtxImpl::write(const std::string& oid, bufferlist& bl, size_t len,
561 uint64_t off, const SnapContext &snapc) {
562 if (get_snap_read() != CEPH_NOSNAP) {
563 return -EROFS;
564 } else if (m_client->is_blacklisted()) {
565 return -EBLACKLISTED;
566 }
567
568 TestMemCluster::SharedFile file;
569 {
570 RWLock::WLocker l(m_pool->file_lock);
571 file = get_file(oid, true, snapc);
572 }
573
574 RWLock::WLocker l(file->lock);
575 if (len > 0) {
576 interval_set<uint64_t> is;
577 is.insert(off, len);
578 is.intersection_of(file->snap_overlap);
579 file->snap_overlap.subtract(is);
580 }
581
582 ensure_minimum_length(off + len, &file->data);
583 file->data.copy_in(off, len, bl);
584 return 0;
585 }
586
587 int TestMemIoCtxImpl::write_full(const std::string& oid, bufferlist& bl,
588 const SnapContext &snapc) {
589 if (get_snap_read() != CEPH_NOSNAP) {
590 return -EROFS;
591 } else if (m_client->is_blacklisted()) {
592 return -EBLACKLISTED;
593 }
594
595 TestMemCluster::SharedFile file;
596 {
597 RWLock::WLocker l(m_pool->file_lock);
598 file = get_file(oid, true, snapc);
599 if (file == NULL) {
600 return -ENOENT;
601 }
602 }
603
604 RWLock::WLocker l(file->lock);
605 if (bl.length() > 0) {
606 interval_set<uint64_t> is;
607 is.insert(0, bl.length());
608 is.intersection_of(file->snap_overlap);
609 file->snap_overlap.subtract(is);
610 }
611
612 file->data.clear();
613 ensure_minimum_length(bl.length(), &file->data);
614 file->data.copy_in(0, bl.length(), bl);
615 return 0;
616 }
617
618 int TestMemIoCtxImpl::writesame(const std::string& oid, bufferlist& bl, size_t len,
619 uint64_t off, const SnapContext &snapc) {
620 if (get_snap_read() != CEPH_NOSNAP) {
621 return -EROFS;
622 } else if (m_client->is_blacklisted()) {
623 return -EBLACKLISTED;
624 }
625
626 if (len == 0 || (len % bl.length())) {
627 return -EINVAL;
628 }
629
630 TestMemCluster::SharedFile file;
631 {
632 RWLock::WLocker l(m_pool->file_lock);
633 file = get_file(oid, true, snapc);
634 }
635
636 RWLock::WLocker l(file->lock);
637 if (len > 0) {
638 interval_set<uint64_t> is;
639 is.insert(off, len);
640 is.intersection_of(file->snap_overlap);
641 file->snap_overlap.subtract(is);
642 }
643
644 ensure_minimum_length(off + len, &file->data);
645 while (len > 0) {
646 file->data.copy_in(off, bl.length(), bl);
647 off += bl.length();
648 len -= bl.length();
649 }
650 return 0;
651 }
652
653 int TestMemIoCtxImpl::cmpext(const std::string& oid, uint64_t off,
654 bufferlist& cmp_bl) {
655 if (m_client->is_blacklisted()) {
656 return -EBLACKLISTED;
657 }
658
659 bufferlist read_bl;
660 uint64_t len = cmp_bl.length();
661
662 TestMemCluster::SharedFile file;
663 {
664 RWLock::RLocker l(m_pool->file_lock);
665 file = get_file(oid, false, get_snap_context());
666 if (file == NULL) {
667 return cmpext_compare(cmp_bl, read_bl);
668 }
669 }
670
671 RWLock::RLocker l(file->lock);
672 if (off >= file->data.length()) {
673 len = 0;
674 } else if (off + len > file->data.length()) {
675 len = file->data.length() - off;
676 }
677 read_bl.substr_of(file->data, off, len);
678 return cmpext_compare(cmp_bl, read_bl);
679 }
680
681 int TestMemIoCtxImpl::xattr_get(const std::string& oid,
682 std::map<std::string, bufferlist>* attrset) {
683 if (m_client->is_blacklisted()) {
684 return -EBLACKLISTED;
685 }
686
687 TestMemCluster::SharedFile file;
688 RWLock::RLocker l(m_pool->file_lock);
689 TestMemCluster::FileXAttrs::iterator it = m_pool->file_xattrs.find(
690 {get_namespace(), oid});
691 if (it == m_pool->file_xattrs.end()) {
692 return -ENODATA;
693 }
694 *attrset = it->second;
695 return 0;
696 }
697
698 int TestMemIoCtxImpl::xattr_set(const std::string& oid, const std::string &name,
699 bufferlist& bl) {
700 if (m_client->is_blacklisted()) {
701 return -EBLACKLISTED;
702 }
703
704 RWLock::WLocker l(m_pool->file_lock);
705 m_pool->file_xattrs[{get_namespace(), oid}][name] = bl;
706 return 0;
707 }
708
709 int TestMemIoCtxImpl::zero(const std::string& oid, uint64_t off, uint64_t len,
710 const SnapContext &snapc) {
711 if (m_client->is_blacklisted()) {
712 return -EBLACKLISTED;
713 }
714
715 bool truncate_redirect = false;
716 TestMemCluster::SharedFile file;
717 {
718 RWLock::WLocker l(m_pool->file_lock);
719 file = get_file(oid, false, snapc);
720 if (!file) {
721 return 0;
722 }
723 file = get_file(oid, true, snapc);
724
725 RWLock::RLocker l2(file->lock);
726 if (len > 0 && off + len >= file->data.length()) {
727 // Zero -> Truncate logic embedded in OSD
728 truncate_redirect = true;
729 }
730 }
731 if (truncate_redirect) {
732 return truncate(oid, off, snapc);
733 }
734
735 bufferlist bl;
736 bl.append_zero(len);
737 return write(oid, bl, len, off, snapc);
738 }
739
740 void TestMemIoCtxImpl::append_clone(bufferlist& src, bufferlist* dest) {
741 // deep-copy the src to ensure our memory-based mock RADOS data cannot
742 // be modified by callers
743 if (src.length() > 0) {
744 bufferlist::iterator iter = src.begin();
745 buffer::ptr ptr;
746 iter.copy_deep(src.length(), ptr);
747 dest->append(ptr);
748 }
749 }
750
751 size_t TestMemIoCtxImpl::clip_io(size_t off, size_t len, size_t bl_len) {
752 if (off >= bl_len) {
753 len = 0;
754 } else if (off + len > bl_len) {
755 len = bl_len - off;
756 }
757 return len;
758 }
759
760 void TestMemIoCtxImpl::ensure_minimum_length(size_t len, bufferlist *bl) {
761 if (len > bl->length()) {
762 bufferptr ptr(buffer::create(len - bl->length()));
763 ptr.zero();
764 bl->append(ptr);
765 }
766 }
767
768 TestMemCluster::SharedFile TestMemIoCtxImpl::get_file(
769 const std::string &oid, bool write, const SnapContext &snapc) {
770 ceph_assert(m_pool->file_lock.is_locked() || m_pool->file_lock.is_wlocked());
771 ceph_assert(!write || m_pool->file_lock.is_wlocked());
772
773 TestMemCluster::SharedFile file;
774 TestMemCluster::Files::iterator it = m_pool->files.find(
775 {get_namespace(), oid});
776 if (it != m_pool->files.end()) {
777 file = it->second.back();
778 } else if (!write) {
779 return TestMemCluster::SharedFile();
780 }
781
782 if (write) {
783 bool new_version = false;
784 if (!file || !file->exists) {
785 file = TestMemCluster::SharedFile(new TestMemCluster::File());
786 new_version = true;
787 } else {
788 if (!snapc.snaps.empty() && file->snap_id < snapc.seq) {
789 for (std::vector<snapid_t>::const_reverse_iterator seq_it =
790 snapc.snaps.rbegin();
791 seq_it != snapc.snaps.rend(); ++seq_it) {
792 if (*seq_it > file->snap_id && *seq_it <= snapc.seq) {
793 file->snaps.push_back(*seq_it);
794 }
795 }
796
797 bufferlist prev_data = file->data;
798 file = TestMemCluster::SharedFile(
799 new TestMemCluster::File(*file));
800 file->data.clear();
801 append_clone(prev_data, &file->data);
802 if (prev_data.length() > 0) {
803 file->snap_overlap.insert(0, prev_data.length());
804 }
805 new_version = true;
806 }
807 }
808
809 if (new_version) {
810 file->snap_id = snapc.seq;
811 file->mtime = ceph_clock_now().sec();
812 m_pool->files[{get_namespace(), oid}].push_back(file);
813 }
814 return file;
815 }
816
817 if (get_snap_read() == CEPH_NOSNAP) {
818 if (!file->exists) {
819 ceph_assert(it->second.size() > 1);
820 return TestMemCluster::SharedFile();
821 }
822 return file;
823 }
824
825 TestMemCluster::FileSnapshots &snaps = it->second;
826 for (TestMemCluster::FileSnapshots::reverse_iterator it = snaps.rbegin();
827 it != snaps.rend(); ++it) {
828 TestMemCluster::SharedFile file = *it;
829 if (file->snap_id < get_snap_read()) {
830 if (!file->exists) {
831 return TestMemCluster::SharedFile();
832 }
833 return file;
834 }
835 }
836 return TestMemCluster::SharedFile();
837 }
838
839 } // namespace librados