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