be/src/storage/mow/key_probe.h
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. 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, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | #pragma once |
19 | | |
20 | | #include <cstdint> |
21 | | #include <memory> |
22 | | #include <string> |
23 | | #include <vector> |
24 | | |
25 | | #include "common/status.h" |
26 | | #include "storage/olap_common.h" |
27 | | #include "storage/rowset/rowset_fwd.h" |
28 | | #include "storage/utils.h" |
29 | | |
30 | | namespace doris { |
31 | | class BaseTablet; |
32 | | class IOlapColumnDataAccessor; |
33 | | class RowKeyEncoder; |
34 | | class TabletSchema; |
35 | | class SegmentCacheHandle; |
36 | | struct MowContext; |
37 | | struct PartialUpdateStats; |
38 | | |
39 | | namespace segment_v2 { |
40 | | |
41 | | // Result of looking up one primary key in a merge-on-write load. |
42 | | enum class KeyProbeResult : uint8_t { |
43 | | // Key absent: brand-new row. |
44 | | NOT_FOUND = 0, |
45 | | // Key exists; the incoming row replaces the old one. |
46 | | FOUND = 1, |
47 | | // Stored row has a larger sequence value, so the incoming row loses. |
48 | | FOUND_NEWER = 2, |
49 | | }; |
50 | | |
51 | | struct ProbeOutcome { |
52 | | KeyProbeResult result {KeyProbeResult::NOT_FOUND}; |
53 | | // Only meaningful when result != NOT_FOUND; a miss leaves it default-constructed. |
54 | | RowLocation loc; |
55 | | // Keeps the rowset holding `loc` alive while the caller reads old-row columns. |
56 | | RowsetSharedPtr rowset; |
57 | | // true -> cells not given in the input take their default/null value |
58 | | // false -> the old row at `loc` must be read into the fill plan |
59 | | bool use_default_or_null {true}; |
60 | | }; |
61 | | |
62 | | // The old row plus its encoded sequence value, returned by probe_previous_seq_value. The sequence |
63 | | // value is empty unless outcome.result is FOUND. |
64 | | struct PrevSeqProbe { |
65 | | ProbeOutcome outcome; |
66 | | std::string encoded_seq_value; |
67 | | }; |
68 | | |
69 | | // IMPORTANT: probe() applies delete-bitmap marks right away (not batched), using |
70 | | // TEMP_VERSION_COMMON. Segcompaction and the pre-commit checks read these TEMP marks mid-load, so |
71 | | // delaying them would lose deletes. |
72 | | class MowKeyProbe { |
73 | | public: |
74 | | // Which rows this probe marks deleted in mow_context->delete_bitmap. |
75 | | enum class MarkDeleted : uint8_t { |
76 | | // Pure lookup: marking is somebody else's job (the row binlog history read). |
77 | | NONE = 0, |
78 | | // Mark the old row, i.e. the row already in the table that the incoming row replaces. On a |
79 | | // sequence loss nothing is marked at all: the caller of this mode drops the losing row |
80 | | // itself instead of writing it into the segment. |
81 | | OLD_ROW = 1, |
82 | | // Mark the old row, and the incoming row too when it loses on sequence: the writer has |
83 | | // already written that row into the segment, so it cannot just be dropped. |
84 | | OLD_AND_LOSING_ROW = 2, |
85 | | }; |
86 | | |
87 | | // The use_defaults_* flags list the situations in which the probe sets |
88 | | // ProbeOutcome::use_default_or_null instead of asking for the old row's values. |
89 | | struct Policy { |
90 | | MarkDeleted mark_deleted {MarkDeleted::OLD_AND_LOSING_ROW}; |
91 | | // Only without a sequence column: that one must survive for merge-on-read compaction. |
92 | | bool use_defaults_for_delete_signed {true}; |
93 | | // A row that loses on sequence does not take effect, so nothing fills it. |
94 | | bool use_defaults_for_seq_loser {true}; |
95 | | // Flexible partial update: the old row was already deleted earlier in this same load, so |
96 | | // the incoming row is brand new. |
97 | | bool use_defaults_for_in_load_deleted {false}; |
98 | | }; |
99 | | |
100 | | // lookup_schema goes to BaseTablet::lookup_row_key; has_sequence_col comes from the input's |
101 | | // schema and drives use_defaults_for_delete_signed; writing_rowset_id/writing_segment_id |
102 | | // identify the segment being written, used only to mark a sequence loser. |
103 | | MowKeyProbe(BaseTablet* tablet, TabletSchema* lookup_schema, bool has_sequence_col, |
104 | | std::shared_ptr<MowContext> mow_context, const RowsetId& writing_rowset_id, |
105 | | uint32_t writing_segment_id, Policy policy); |
106 | | |
107 | | // The partial update fill paths: mark the old row, or the incoming row when it loses on |
108 | | // sequence, and read the old row's values for the columns the input does not carry. Two cases |
109 | | // take defaults instead: a losing row (it never takes effect) and a delete-signed row without a |
110 | | // sequence column (its values are never read back). `flexible` adds the insert-after-delete |
111 | | // rule. |
112 | | static MowKeyProbe for_partial_update(BaseTablet* tablet, TabletSchema* lookup_schema, |
113 | | bool has_sequence_col, |
114 | | std::shared_ptr<MowContext> mow_context, |
115 | | const RowsetId& writing_rowset_id, |
116 | 1.78k | uint32_t writing_segment_id, bool flexible) { |
117 | 1.78k | return MowKeyProbe {tablet, |
118 | 1.78k | lookup_schema, |
119 | 1.78k | has_sequence_col, |
120 | 1.78k | std::move(mow_context), |
121 | 1.78k | writing_rowset_id, |
122 | 1.78k | writing_segment_id, |
123 | 1.78k | Policy { |
124 | 1.78k | .mark_deleted = MarkDeleted::OLD_AND_LOSING_ROW, |
125 | 1.78k | .use_defaults_for_delete_signed = true, |
126 | 1.78k | .use_defaults_for_seq_loser = true, |
127 | 1.78k | .use_defaults_for_in_load_deleted = flexible, |
128 | 1.78k | }}; |
129 | 1.78k | } |
130 | | |
131 | | // The row binlog history lookup: marks nothing, and keeps the old values of a sequence loser, |
132 | | // and of a delete-signed row when a __BEFORE__* image is wanted. |
133 | | static MowKeyProbe for_row_binlog(BaseTablet* tablet, TabletSchema* lookup_schema, |
134 | | bool has_sequence_col, |
135 | 8 | std::shared_ptr<MowContext> mow_context, bool write_before) { |
136 | 8 | return MowKeyProbe {tablet, |
137 | 8 | lookup_schema, |
138 | 8 | has_sequence_col, |
139 | 8 | std::move(mow_context), |
140 | 8 | RowsetId {}, |
141 | 8 | 0, |
142 | 8 | Policy { |
143 | 8 | .mark_deleted = MarkDeleted::NONE, |
144 | 8 | .use_defaults_for_delete_signed = !write_before, |
145 | 8 | .use_defaults_for_seq_loser = false, |
146 | 8 | .use_defaults_for_in_load_deleted = false, |
147 | 8 | }}; |
148 | 8 | } |
149 | | |
150 | | // Probe one row. `key` is the full encoded key (with seq suffix when key_has_seq_suffix). |
151 | | // `segment_pos` is the row's position in the segment being written (self-mark only). `stats` |
152 | | // counts new/updated/deleted rows, except under MarkDeleted::NONE which counts nothing; a |
153 | | // caller that doesn't track partial-update counts passes a throwaway. |
154 | | // |
155 | | // On NOT_FOUND it bumps stats.num_rows_new_added, but PartialUpdateInfo::handle_new_key() needs |
156 | | // caller-side state, so the partial update callers still run it themselves. |
157 | | Result<ProbeOutcome> probe(const std::string& key, size_t segment_pos, bool key_has_seq_suffix, |
158 | | bool have_delete_sign, |
159 | | const std::vector<RowsetSharedPtr>& specified_rowsets, |
160 | | std::vector<std::unique_ptr<SegmentCacheHandle>>& segment_caches, |
161 | | PartialUpdateStats& stats) const; |
162 | | |
163 | | // Lookup without the seq suffix; returns the old row plus its encoded sequence value |
164 | | // (BlockAggregator). Never touches the delete bitmap, and ignores the policy entirely. |
165 | | Result<PrevSeqProbe> probe_previous_seq_value( |
166 | | const std::string& key, const std::vector<RowsetSharedPtr>& specified_rowsets, |
167 | | std::vector<std::unique_ptr<SegmentCacheHandle>>& segment_caches) const; |
168 | | |
169 | | // Erase the row-cache entry. Erase-only: the rowset isn't visible yet, so inserting could |
170 | | // expose uncommitted data if the load fails. |
171 | | static void maybe_invalidate_row_cache(int64_t tablet_id, const TabletSchema& schema, |
172 | | DataWriteType write_type, const std::string& key); |
173 | | |
174 | | private: |
175 | | BaseTablet* _tablet = nullptr; |
176 | | TabletSchema* _lookup_schema = nullptr; |
177 | | bool _has_sequence_col = false; |
178 | | std::shared_ptr<MowContext> _mow_context; |
179 | | RowsetId _writing_rowset_id; |
180 | | uint32_t _writing_segment_id = 0; |
181 | | Policy _policy; |
182 | | }; |
183 | | |
184 | | std::string encode_mow_key_invalidate_cache( |
185 | | const RowKeyEncoder& key_encoder, const std::vector<IOlapColumnDataAccessor*>& key_columns, |
186 | | const IOlapColumnDataAccessor* seq_column, size_t pos, bool row_has_seq, int64_t tablet_id, |
187 | | const TabletSchema& schema, DataWriteType write_type); |
188 | | |
189 | | } // namespace segment_v2 |
190 | | } // namespace doris |