/Users/deen/code/yugabyte-db/src/yb/tablet/operations/change_metadata_operation.cc
| Line | Count | Source (jump to first uncovered line) | 
| 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 |  | // The following only applies to changes made to this file as part of YugaByte development. | 
| 19 |  | // | 
| 20 |  | // Portions Copyright (c) YugaByte, Inc. | 
| 21 |  | // | 
| 22 |  | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except | 
| 23 |  | // in compliance with the License.  You may obtain a copy of the License at | 
| 24 |  | // | 
| 25 |  | // http://www.apache.org/licenses/LICENSE-2.0 | 
| 26 |  | // | 
| 27 |  | // Unless required by applicable law or agreed to in writing, software distributed under the License | 
| 28 |  | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express | 
| 29 |  | // or implied.  See the License for the specific language governing permissions and limitations | 
| 30 |  | // under the License. | 
| 31 |  | // | 
| 32 |  |  | 
| 33 |  | #include "yb/tablet/operations/change_metadata_operation.h" | 
| 34 |  |  | 
| 35 |  | #include <glog/logging.h> | 
| 36 |  |  | 
| 37 |  | #include "yb/common/schema.h" | 
| 38 |  | #include "yb/common/wire_protocol.h" | 
| 39 |  |  | 
| 40 |  | #include "yb/consensus/consensus_round.h" | 
| 41 |  | #include "yb/consensus/log.h" | 
| 42 |  |  | 
| 43 |  | #include "yb/tablet/tablet.h" | 
| 44 |  | #include "yb/tablet/tablet_metadata.h" | 
| 45 |  | #include "yb/tablet/tablet_peer.h" | 
| 46 |  |  | 
| 47 |  | #include "yb/tserver/tserver_error.h" | 
| 48 |  |  | 
| 49 |  | #include "yb/util/async_util.h" | 
| 50 |  | #include "yb/util/logging.h" | 
| 51 |  | #include "yb/util/status_format.h" | 
| 52 |  | #include "yb/util/trace.h" | 
| 53 |  |  | 
| 54 |  | namespace yb { | 
| 55 |  | namespace tablet { | 
| 56 |  |  | 
| 57 |  | using google::protobuf::RepeatedPtrField; | 
| 58 |  | using tserver::TabletServerErrorPB; | 
| 59 |  |  | 
| 60 |  | template <> | 
| 61 |  | void RequestTraits<ChangeMetadataRequestPB>::SetAllocatedRequest( | 
| 62 | 0 |     consensus::ReplicateMsg* replicate, ChangeMetadataRequestPB* request) { | 
| 63 | 0 |   replicate->set_allocated_change_metadata_request(request); | 
| 64 | 0 | } | 
| 65 |  |  | 
| 66 |  | template <> | 
| 67 |  | ChangeMetadataRequestPB* RequestTraits<ChangeMetadataRequestPB>::MutableRequest( | 
| 68 | 769k |     consensus::ReplicateMsg* replicate) { | 
| 69 | 769k |   return replicate->mutable_change_metadata_request(); | 
| 70 | 769k | } | 
| 71 |  |  | 
| 72 |  | ChangeMetadataOperation::ChangeMetadataOperation( | 
| 73 |  |     Tablet* tablet, log::Log* log, const ChangeMetadataRequestPB* request) | 
| 74 | 546k |     : ExclusiveSchemaOperation(tablet, request), log_(log) { | 
| 75 | 546k | } | 
| 76 |  |  | 
| 77 |  | ChangeMetadataOperation::ChangeMetadataOperation(const ChangeMetadataRequestPB* request) | 
| 78 | 1.64k |     : ChangeMetadataOperation(nullptr, nullptr, request) { | 
| 79 | 1.64k | } Unexecuted instantiation: _ZN2yb6tablet23ChangeMetadataOperationC2EPKNS0_23ChangeMetadataRequestPBE_ZN2yb6tablet23ChangeMetadataOperationC1EPKNS0_23ChangeMetadataRequestPBE| Line | Count | Source |  | 78 | 1.64k |     : ChangeMetadataOperation(nullptr, nullptr, request) { |  | 79 | 1.64k | } | 
 | 
| 80 |  |  | 
| 81 | 547k | ChangeMetadataOperation::~ChangeMetadataOperation() = default; | 
| 82 |  |  | 
| 83 | 545k | void ChangeMetadataOperation::SetIndexes(const RepeatedPtrField<IndexInfoPB>& indexes) { | 
| 84 | 545k |   index_map_.FromPB(indexes); | 
| 85 | 545k | } | 
| 86 |  |  | 
| 87 | 2.59k | string ChangeMetadataOperation::ToString() const { | 
| 88 | 2.59k |   return Format("ChangeMetadataOperation { hybrid_time: $0 schema: $1 request: $2 }", | 
| 89 | 2.59k |                 hybrid_time_even_if_unset(), schema_, request()); | 
| 90 | 2.59k | } | 
| 91 |  |  | 
| 92 | 545k | Status ChangeMetadataOperation::Prepare() { | 
| 93 | 545k |   TRACE("PREPARE CHANGE-METADATA: Starting"); | 
| 94 |  |  | 
| 95 |  |   // Decode schema | 
| 96 | 545k |   auto has_schema = request()->has_schema(); | 
| 97 | 545k |   if (has_schema) { | 
| 98 | 49.0k |     schema_holder_ = std::make_unique<Schema>(); | 
| 99 | 49.0k |     Status s = SchemaFromPB(request()->schema(), schema_holder_.get()); | 
| 100 | 49.0k |     if (!s.ok()) { | 
| 101 | 0 |       return s.CloneAndAddErrorCode( | 
| 102 | 0 |           tserver::TabletServerError(TabletServerErrorPB::INVALID_SCHEMA)); | 
| 103 | 0 |     } | 
| 104 | 545k |   } | 
| 105 |  |  | 
| 106 | 545k |   Tablet* tablet = this->tablet(); | 
| 107 | 545k |   RETURN_NOT_OK(tablet->CreatePreparedChangeMetadata(this, schema_holder_.get())); | 
| 108 |  |  | 
| 109 | 545k |   SetIndexes(request()->indexes()); | 
| 110 |  |  | 
| 111 | 545k |   TRACE("PREPARE CHANGE-METADATA: finished"); | 
| 112 | 545k |   return Status::OK(); | 
| 113 | 545k | } | 
| 114 |  |  | 
| 115 | 545k | Status ChangeMetadataOperation::DoReplicated(int64_t leader_term, Status* complete_status) { | 
| 116 | 545k |   TRACE("APPLY CHANGE-METADATA: Starting"); | 
| 117 |  |  | 
| 118 | 545k |   Tablet* tablet = this->tablet(); | 
| 119 | 545k |   log::Log* log = mutable_log(); | 
| 120 | 545k |   size_t num_operations = 0; | 
| 121 |  |  | 
| 122 | 545k |   if (request()->has_wal_retention_secs()) { | 
| 123 |  |     // We don't consider wal retention changes as another operation because this value is always | 
| 124 |  |     // sent together with the schema, as long as it has been changed in the master's sys-catalog. | 
| 125 | 2.55k |     auto s = tablet->AlterWalRetentionSecs(this); | 
| 126 | 2.55k |     if (s.ok()) { | 
| 127 | 2.55k |       log->set_wal_retention_secs(request()->wal_retention_secs()); | 
| 128 | 18.4E |     } else { | 
| 129 | 18.4E |       LOG(WARNING) << "T " << tablet->tablet_id() << ": Unable to alter wal retention secs"; | 
| 130 | 18.4E |     } | 
| 131 | 2.55k |   } | 
| 132 |  |  | 
| 133 |  |   // Only perform one operation. | 
| 134 | 545k |   enum MetadataChange { | 
| 135 | 545k |     NONE, | 
| 136 | 545k |     SCHEMA, | 
| 137 | 545k |     ADD_TABLE, | 
| 138 | 545k |     REMOVE_TABLE, | 
| 139 | 545k |     BACKFILL_DONE, | 
| 140 | 545k |   }; | 
| 141 |  |  | 
| 142 | 545k |   MetadataChange metadata_change = MetadataChange::NONE; | 
| 143 | 545k |   bool request_has_newer_schema = false; | 
| 144 | 545k |   if (request()->has_schema()) { | 
| 145 | 49.0k |     metadata_change = MetadataChange::SCHEMA; | 
| 146 | 49.0k |     request_has_newer_schema = tablet->metadata()->schema_version() < schema_version(); | 
| 147 | 49.0k |     if (request_has_newer_schema) { | 
| 148 | 46.6k |       ++num_operations; | 
| 149 | 46.6k |     } | 
| 150 | 49.0k |   } | 
| 151 |  |  | 
| 152 | 545k |   if (request()->has_add_table()) { | 
| 153 | 489k |     metadata_change = MetadataChange::NONE; | 
| 154 | 489k |     if (++num_operations == 1) { | 
| 155 | 489k |       metadata_change = MetadataChange::ADD_TABLE; | 
| 156 | 489k |     } | 
| 157 | 489k |   } | 
| 158 |  |  | 
| 159 | 545k |   if (request()->has_remove_table_id()) { | 
| 160 | 45 |     metadata_change = MetadataChange::NONE; | 
| 161 | 45 |     if (++num_operations == 1) { | 
| 162 | 45 |       metadata_change = MetadataChange::REMOVE_TABLE; | 
| 163 | 45 |     } | 
| 164 | 45 |   } | 
| 165 |  |  | 
| 166 | 545k |   if (request()->has_mark_backfill_done()) { | 
| 167 | 7.28k |     metadata_change = MetadataChange::NONE; | 
| 168 | 7.28k |     if (++num_operations == 1) { | 
| 169 | 7.28k |       metadata_change = MetadataChange::BACKFILL_DONE; | 
| 170 | 7.28k |     } | 
| 171 | 7.28k |   } | 
| 172 |  |  | 
| 173 | 545k |   switch (metadata_change) { | 
| 174 | 0 |     case MetadataChange::NONE: | 
| 175 | 0 |       return STATUS_FORMAT( | 
| 176 | 0 |           InvalidArgument, "Wrong number of operations in Change Metadata Operation: $0", | 
| 177 | 0 |           num_operations); | 
| 178 | 49.2k |     case MetadataChange::SCHEMA: | 
| 179 | 49.2k |       if (!request_has_newer_schema) { | 
| 180 | 2.59k |         LOG_WITH_PREFIX(INFO) | 
| 181 | 2.59k |             << "Already running schema version " << tablet->metadata()->schema_version() | 
| 182 | 2.59k |             << " got alter request for version " << schema_version(); | 
| 183 | 2.59k |         break; | 
| 184 | 2.59k |       } | 
| 185 | 0 |       DCHECK_EQ(1, num_operations) << "Invalid number of change metadata operations: " | 
| 186 | 0 |                                    << num_operations; | 
| 187 | 46.6k |       RETURN_NOT_OK(tablet->AlterSchema(this)); | 
| 188 | 46.6k |       log->SetSchemaForNextLogSegment(*DCHECK_NOTNULL(schema()), schema_version()); | 
| 189 | 46.6k |       break; | 
| 190 | 489k |     case MetadataChange::ADD_TABLE: | 
| 191 | 0 |       DCHECK_EQ(1, num_operations) << "Invalid number of change metadata operations: " | 
| 192 | 0 |                                    << num_operations; | 
| 193 | 489k |       RETURN_NOT_OK(tablet->AddTable(request()->add_table())); | 
| 194 | 489k |       break; | 
| 195 | 45 |     case MetadataChange::REMOVE_TABLE: | 
| 196 | 0 |       DCHECK_EQ(1, num_operations) << "Invalid number of change metadata operations: " | 
| 197 | 0 |                                    << num_operations; | 
| 198 | 45 |       RETURN_NOT_OK(tablet->RemoveTable(request()->remove_table_id())); | 
| 199 | 45 |       break; | 
| 200 | 7.29k |     case MetadataChange::BACKFILL_DONE: | 
| 201 | 0 |       DCHECK_EQ(1, num_operations) << "Invalid number of change metadata operations: " | 
| 202 | 0 |                                    << num_operations; | 
| 203 | 7.29k |       RETURN_NOT_OK(tablet->MarkBackfillDone(request()->backfill_done_table_id())); | 
| 204 | 7.29k |       break; | 
| 205 | 545k |   } | 
| 206 |  |  | 
| 207 |  |   // Now that all of the changes have been applied and the commit is durable | 
| 208 |  |   // make the changes visible to readers. | 
| 209 | 545k |   TRACE("AlterSchemaCommitCallback: making alter schema visible"); | 
| 210 | 545k |   return Status::OK(); | 
| 211 | 545k | } | 
| 212 |  |  | 
| 213 | 12 | Status ChangeMetadataOperation::DoAborted(const Status& status) { | 
| 214 | 12 |   TRACE("AlterSchemaCommitCallback: transaction aborted"); | 
| 215 | 12 |   return status; | 
| 216 | 12 | } | 
| 217 |  |  | 
| 218 |  | CHECKED_STATUS SyncReplicateChangeMetadataOperation( | 
| 219 |  |     const ChangeMetadataRequestPB* req, | 
| 220 |  |     TabletPeer* tablet_peer, | 
| 221 | 204k |     int64_t term) { | 
| 222 | 204k |   auto operation = std::make_unique<ChangeMetadataOperation>( | 
| 223 | 204k |       tablet_peer->tablet(), tablet_peer->log(), req); | 
| 224 |  |  | 
| 225 | 204k |   Synchronizer synchronizer; | 
| 226 |  |  | 
| 227 | 204k |   operation->set_completion_callback(synchronizer.AsStdStatusCallback()); | 
| 228 |  |  | 
| 229 | 204k |   tablet_peer->Submit(std::move(operation), term); | 
| 230 |  |  | 
| 231 | 204k |   return synchronizer.Wait(); | 
| 232 | 204k | } | 
| 233 |  |  | 
| 234 |  | }  // namespace tablet | 
| 235 |  | }  // namespace yb |