]>
git.proxmox.com Git - ceph.git/blob - ceph/src/osd/ECTransaction.h
036c8ca8d3d26da60fdbf3868b0aa07d921d7589
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2013 Inktank Storage, Inc.
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #ifndef ECTRANSACTION_H
16 #define ECTRANSACTION_H
19 #include "PGBackend.h"
21 #include "erasure-code/ErasureCodeInterface.h"
22 #include "PGTransaction.h"
23 #include "ExtentCache.h"
25 namespace ECTransaction
{
28 bool invalidates_cache
= false; // Yes, both are possible
29 map
<hobject_t
,extent_set
> to_read
;
30 map
<hobject_t
,extent_set
> will_write
; // superset of to_read
32 map
<hobject_t
,ECUtil::HashInfoRef
> hash_infos
;
35 bool requires_overwrite(
37 const PGTransaction::ObjectOperation
&op
);
40 WritePlan
get_write_plan(
41 const ECUtil::stripe_info_t
&sinfo
,
42 PGTransactionUPtr
&&t
,
44 DoutPrefixProvider
*dpp
) {
46 t
->safe_create_traverse(
47 [&](pair
<const hobject_t
, PGTransaction::ObjectOperation
> &i
) {
48 ECUtil::HashInfoRef hinfo
= get_hinfo(i
.first
);
49 plan
.hash_infos
[i
.first
] = hinfo
;
51 uint64_t projected_size
=
52 hinfo
->get_projected_total_logical_size(sinfo
);
54 if (i
.second
.has_source()) {
55 plan
.invalidates_cache
= true;
58 if (i
.second
.deletes_first()) {
59 ldpp_dout(dpp
, 20) << __func__
<< ": delete, setting projected size"
65 if (i
.second
.has_source(&source
)) {
66 ECUtil::HashInfoRef shinfo
= get_hinfo(source
);
67 projected_size
= shinfo
->get_projected_total_logical_size(sinfo
);
68 plan
.hash_infos
[source
] = shinfo
;
71 auto &will_write
= plan
.will_write
[i
.first
];
72 if (i
.second
.truncate
&&
73 i
.second
.truncate
->first
< projected_size
) {
74 if (!(sinfo
.logical_offset_is_stripe_aligned(
75 i
.second
.truncate
->first
))) {
76 plan
.to_read
[i
.first
].union_insert(
77 sinfo
.logical_to_prev_stripe_offset(i
.second
.truncate
->first
),
78 sinfo
.get_stripe_width());
80 ldpp_dout(dpp
, 20) << __func__
<< ": unaligned truncate" << dendl
;
82 will_write
.union_insert(
83 sinfo
.logical_to_prev_stripe_offset(i
.second
.truncate
->first
),
84 sinfo
.get_stripe_width());
86 projected_size
= sinfo
.logical_to_next_stripe_offset(
87 i
.second
.truncate
->first
);
90 extent_set raw_write_set
;
91 for (auto &&extent
: i
.second
.buffer_updates
) {
92 using BufferUpdate
= PGTransaction::ObjectOperation::BufferUpdate
;
93 if (boost::get
<BufferUpdate::CloneRange
>(&(extent
.get_val()))) {
96 "CloneRange is not allowed, do_op should have returned ENOTSUPP");
98 raw_write_set
.insert(extent
.get_off(), extent
.get_len());
101 auto orig_size
= projected_size
;
102 for (auto extent
= raw_write_set
.begin();
103 extent
!= raw_write_set
.end();
105 uint64_t head_start
=
106 sinfo
.logical_to_prev_stripe_offset(extent
.get_start());
107 uint64_t head_finish
=
108 sinfo
.logical_to_next_stripe_offset(extent
.get_start());
109 if (head_start
> projected_size
) {
110 head_start
= projected_size
;
112 if (head_start
!= head_finish
&&
113 head_start
< orig_size
) {
114 assert(head_finish
<= orig_size
);
115 assert(head_finish
- head_start
== sinfo
.get_stripe_width());
116 ldpp_dout(dpp
, 20) << __func__
<< ": reading partial head stripe "
117 << head_start
<< "~" << sinfo
.get_stripe_width()
119 plan
.to_read
[i
.first
].union_insert(
120 head_start
, sinfo
.get_stripe_width());
123 uint64_t tail_start
=
124 sinfo
.logical_to_prev_stripe_offset(
125 extent
.get_start() + extent
.get_len());
126 uint64_t tail_finish
=
127 sinfo
.logical_to_next_stripe_offset(
128 extent
.get_start() + extent
.get_len());
129 if (tail_start
!= tail_finish
&&
130 (head_start
== head_finish
|| tail_start
!= head_start
) &&
131 tail_start
< orig_size
) {
132 assert(tail_finish
<= orig_size
);
133 assert(tail_finish
- tail_start
== sinfo
.get_stripe_width());
134 ldpp_dout(dpp
, 20) << __func__
<< ": reading partial tail stripe "
135 << tail_start
<< "~" << sinfo
.get_stripe_width()
137 plan
.to_read
[i
.first
].union_insert(
138 tail_start
, sinfo
.get_stripe_width());
141 if (head_start
!= tail_finish
) {
143 sinfo
.logical_offset_is_stripe_aligned(
144 tail_finish
- head_start
)
146 will_write
.union_insert(
147 head_start
, tail_finish
- head_start
);
148 if (tail_finish
> projected_size
)
149 projected_size
= tail_finish
;
151 assert(tail_finish
<= projected_size
);
155 if (i
.second
.truncate
&&
156 i
.second
.truncate
->second
> projected_size
) {
157 uint64_t truncating_to
=
158 sinfo
.logical_to_next_stripe_offset(i
.second
.truncate
->second
);
159 ldpp_dout(dpp
, 20) << __func__
<< ": truncating out to "
162 will_write
.union_insert(projected_size
,
163 truncating_to
- projected_size
);
164 projected_size
= truncating_to
;
167 ldpp_dout(dpp
, 20) << __func__
<< ": " << i
.first
168 << " projected size "
171 hinfo
->set_projected_total_logical_size(
175 /* validate post conditions:
176 * to_read should have an entry for i.first iff it isn't empty
177 * and if we are reading from i.first, we can't be renaming or
179 assert(plan
.to_read
.count(i
.first
) == 0 ||
180 (!plan
.to_read
.at(i
.first
).empty() &&
181 !i
.second
.has_source()));
183 plan
.t
= std::move(t
);
187 void generate_transactions(
189 ErasureCodeInterfaceRef
&ecimpl
,
191 bool legacy_log_entries
,
192 const ECUtil::stripe_info_t
&sinfo
,
193 const map
<hobject_t
,extent_map
> &partial_extents
,
194 vector
<pg_log_entry_t
> &entries
,
195 map
<hobject_t
,extent_map
> *written
,
196 map
<shard_id_t
, ObjectStore::Transaction
> *transactions
,
197 set
<hobject_t
> *temp_added
,
198 set
<hobject_t
> *temp_removed
,
199 DoutPrefixProvider
*dpp
);