0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
OperationAlterTable.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2015 Hypertable, Inc.
3  *
4  * This file is part of Hypertable.
5  *
6  * Hypertable is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; version 3 of the
9  * License, or any later version.
10  *
11  * Hypertable is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
26 
27 #include <Common/Compat.h>
28 #include "OperationAlterTable.h"
29 
36 
37 #include <Hyperspace/Session.h>
38 
39 #include <Hypertable/Lib/Key.h>
41 
42 #include <Common/Error.h>
43 #include <Common/FailureInducer.h>
44 #include <Common/ScopeGuard.h>
45 #include <Common/Serialization.h>
46 #include <Common/Time.h>
47 
48 #include <boost/algorithm/string.hpp>
49 
50 #include <chrono>
51 #include <thread>
52 
53 using namespace Hypertable;
54 using namespace Hyperspace;
55 using namespace std;
56 
58  const MetaLog::EntityHeader &header_)
59  : Operation(context, header_) {
60 }
61 
63  : Operation(context, event, MetaLog::EntityType::OPERATION_ALTER_TABLE) {
64  const uint8_t *ptr = event->payload;
65  size_t remaining = event->payload_len;
66  m_params.decode(&ptr, &remaining);
67  m_exclusivities.insert(m_params.name());
69 }
70 
201  bool is_namespace;
202  StringSet servers;
203  DispatchHandlerOperationPtr op_handler;
204  TableIdentifier table;
205  int32_t state = get_state();
207  SchemaPtr original_schema;
208  SchemaPtr alter_schema;
209 
210  HT_INFOF("Entering AlterTable-%lld(%s) state=%s",
211  (Lld)header.id, m_params.name().c_str(), OperationState::get_text(state));
212 
213  switch (state) {
214 
216  // Check to see if namespace exists
217  if(m_context->namemap->name_to_id(m_params.name(), m_id, &is_namespace)) {
218  if (is_namespace) {
219  complete_error(Error::INVALID_ARGUMENT, format("%s is a namespace", m_params.name().c_str()));
220  break;
221  }
223  m_context->mml_writer->record_state(shared_from_this());
224  }
225  else {
227  break;
228  }
229  HT_MAYBE_FAIL("alter-table-INITIAL");
230 
232  if (!get_schemas(original_schema, alter_schema))
233  break;
234  if (!m_params.force()) {
235  try {
236  if (original_schema->get_generation() != alter_schema->get_generation())
238  "Expected altered schema generation %lld to match original"
239  " %lld", (Lld)alter_schema->get_generation(),
240  (Lld)original_schema->get_generation());
241 
242  if (!alter_schema->clear_generation_if_changed(*original_schema)) {
243  // No change, therefore nothing to do
244  complete_ok();
245  break;
246  }
247 
248  // Assign new generation number
249  int64_t generation = get_ts64();
250  alter_schema->update_generation(generation);
251  }
252  catch (Exception &e) {
254  HT_ERROR_OUT << e << HT_END;
255  complete_error(e);
256  break;
257  }
258  }
259  m_schema = alter_schema->render_xml(true);
260  {
261  lock_guard<mutex> lock(m_mutex);
262  m_dependencies.clear();
265  }
266  m_parts = get_create_index_parts(original_schema, alter_schema);
267  m_context->mml_writer->record_state(shared_from_this());
268 
271  stage_subop(make_shared<OperationCreateTable>(m_context, m_params.name(), m_schema, m_parts));
273  record_state();
274  break;
275 
277  if (!validate_subops())
278  break;
279  servers.clear();
281  {
282  lock_guard<mutex> lock(m_mutex);
283  m_servers.clear();
284  m_dependencies.clear();
285  for (StringSet::iterator iter=servers.begin(); iter!=servers.end(); ++iter) {
286  if (m_completed.count(*iter) == 0) {
287  m_dependencies.insert(*iter);
288  m_servers.insert(*iter);
289  }
290  }
292  }
293  record_state();
294  break;
295 
297  table.id = m_id.c_str();
298  table.generation = 0;
299  op_handler = make_shared<DispatchHandlerOperationAlterTable>(m_context, table, m_schema);
300  op_handler->start(m_servers);
301  if (!op_handler->wait_for_completion()) {
302  std::set<DispatchHandlerOperation::Result> results;
303  op_handler->get_results(results);
304  for (const auto &result : results) {
305  if (result.error == Error::OK ||
306  result.error == Error::TABLE_NOT_FOUND) {
307  lock_guard<mutex> lock(m_mutex);
308  m_completed.insert(result.location);
309  }
310  else
311  HT_WARNF("Alter table error at %s - %s (%s)", result.location.c_str(),
312  Error::get_text(result.error), result.msg.c_str());
313  }
314  {
315  lock_guard<mutex> lock(m_mutex);
316  m_servers.clear();
317  m_dependencies.clear();
320  }
321  m_context->mml_writer->record_state(shared_from_this());
322  // Sleep a little bit to prevent busy wait
323  this_thread::sleep_for(chrono::milliseconds(5000));
324  return;
325  }
327  m_context->mml_writer->record_state(shared_from_this());
328 
330  if (!get_schemas(original_schema, alter_schema))
331  break;
332  m_parts = get_drop_index_parts(original_schema, alter_schema);
333  {
334  filename = m_context->toplevel_dir + "/tables/" + m_id;
335  m_context->hyperspace->attr_set(filename, OPEN_FLAG_READ|OPEN_FLAG_WRITE|OPEN_FLAG_LOCK_EXCLUSIVE,
336  "schema", m_schema.c_str(), m_schema.length());
337  }
340  m_context->mml_writer->record_state(shared_from_this());
341  }
342  else
343  complete_ok();
344  break;
345 
347  stage_subop(make_shared<OperationToggleTableMaintenance>(m_context, m_params.name(),
350  record_state();
351  break;
352 
354  if (!validate_subops())
355  break;
356  stage_subop(make_shared<OperationDropTable>(m_context, m_params.name(), true, m_parts));
358  record_state();
359  break;
360 
362  if (!validate_subops())
363  break;
364  stage_subop(make_shared<OperationToggleTableMaintenance>(m_context, m_params.name(),
367  record_state();
368  break;
369 
371  if (!validate_subops())
372  break;
373  complete_ok();
374  break;
375 
376  default:
377  HT_FATALF("Unrecognized state %d", state);
378  }
379 
380  HT_INFOF("Leaving AlterTable-%lld (%s) state=%s", (Lld)header.id,
382 }
383 
384 
385 void OperationAlterTable::display_state(std::ostream &os) {
386  os << " name=" << m_params.name() << " id=" << m_id << " ";
387 }
388 
390  return 1;
391 }
392 
394  size_t length = m_params.encoded_length() +
397  length += 4;
398  for (auto &location : m_completed)
399  length += Serialization::encoded_length_vstr(location);
400  length += 4;
401  for (auto &location : m_servers)
402  length += Serialization::encoded_length_vstr(location);
403  length += m_parts.encoded_length();
404  return length;
405 }
406 
407 void OperationAlterTable::encode_state(uint8_t **bufp) const {
408  m_params.encode(bufp);
412  for (auto &location : m_completed)
413  Serialization::encode_vstr(bufp, location);
414  Serialization::encode_i32(bufp, m_servers.size());
415  for (auto &location : m_servers)
416  Serialization::encode_vstr(bufp, location);
417  m_parts.encode(bufp);
418 }
419 
420 void OperationAlterTable::decode_state(uint8_t version, const uint8_t **bufp, size_t *remainp) {
421  m_params.decode(bufp, remainp);
422  m_schema = Serialization::decode_vstr(bufp, remainp);
423  m_id = Serialization::decode_vstr(bufp, remainp);
424  size_t length = Serialization::decode_i32(bufp, remainp);
425  for (size_t i=0; i<length; i++)
426  m_completed.insert( Serialization::decode_vstr(bufp, remainp) );
427  length = Serialization::decode_i32(bufp, remainp);
428  for (size_t i=0; i<length; i++)
429  m_servers.insert( Serialization::decode_vstr(bufp, remainp) );
430  m_parts.decode(bufp, remainp);
431 }
432 
433 void OperationAlterTable::decode_state_old(uint8_t version, const uint8_t **bufp, size_t *remainp) {
434  {
435  string name = Serialization::decode_vstr(bufp, remainp);
436  m_schema = Serialization::decode_vstr(bufp, remainp);
437  bool force {};
438  if (version >= 4)
439  force = Serialization::decode_bool(bufp, remainp);
441  }
442  m_id = Serialization::decode_vstr(bufp, remainp);
443  size_t length = Serialization::decode_i32(bufp, remainp);
444  for (size_t i=0; i<length; i++)
445  m_completed.insert( Serialization::decode_vstr(bufp, remainp) );
446  if (version >= 2) {
447  length = Serialization::decode_i32(bufp, remainp);
448  for (size_t i=0; i<length; i++)
449  m_servers.insert( Serialization::decode_vstr(bufp, remainp) );
450  if (version >= 3) {
451  int8_t parts = (int8_t)Serialization::decode_byte(bufp, remainp);
452  m_parts = TableParts(parts);
453  }
454  }
455 }
456 
458  return "OperationAlterTable";
459 }
460 
462  return String("AlterTable ") + m_params.name();
463 }
464 
466  SchemaPtr &alter_schema) {
467  if (!original_schema || !alter_schema) {
468  try {
469  DynamicBuffer value_buf;
470  string filename = m_context->toplevel_dir + "/tables/" + m_id;
471  m_context->hyperspace->attr_get(filename, "schema", value_buf);
472  original_schema.reset( Schema::new_instance((const char *)value_buf.base) );
473  alter_schema.reset( Schema::new_instance(m_params.schema()) );
474  }
475  catch (Exception &e) {
476  complete_error(e);
477  return false;
478  }
479  }
480  return true;
481 }
482 
484  SchemaPtr &alter_schema) {
485  int8_t parts {};
486  TableParts original_parts = original_schema->get_table_parts();
487  TableParts alter_parts = alter_schema->get_table_parts();
488  if (original_parts.value_index() && !alter_parts.value_index())
489  parts |= TableParts::VALUE_INDEX;
490  if (original_parts.qualifier_index() && !alter_parts.qualifier_index())
492  return TableParts(parts);
493 }
494 
496  SchemaPtr &alter_schema) {
497  int8_t parts {};
498  TableParts original_parts = original_schema->get_table_parts();
499  TableParts alter_parts = alter_schema->get_table_parts();
500  if (!original_parts.value_index() && alter_parts.value_index())
501  parts |= TableParts::VALUE_INDEX;
502  if (!original_parts.qualifier_index() && alter_parts.qualifier_index())
504  return TableParts(parts);
505 }
std::set< String > StringSet
STL Set managing Strings.
Definition: StringExt.h:42
char * decode_vstr(const uint8_t **bufp, size_t *remainp)
Decode a vstr (vint64, data, null).
Declarations for OperationToggleTableMaintenance.
#define HT_WARNF(msg,...)
Definition: Logger.h:290
TableParts get_create_index_parts(SchemaPtr &original_schema, SchemaPtr &alter_schema)
Determines which index tables to create.
The FailureInducer simulates errors.
ContextPtr m_context
Pointer to Master context.
Definition: Operation.h:553
static String filename
Definition: Config.cc:48
const bool OFF
Constant representing off
Request parameters for alter table operation.
Definition: AlterTable.h:46
std::string String
A String is simply a typedef to std::string.
Definition: String.h:44
Declarations for OperationDropTable.
String format(const char *fmt,...)
Returns a String using printf like format facilities Vanilla snprintf is about 1.5x faster than this...
Definition: String.cc:37
bool validate_subops()
Handles the results of sub operations.
Definition: Operation.cc:512
virtual size_t encoded_length() const
Returns serialized object length.
Definition: Serializable.cc:37
int64_t id
Unique ID of entity.
Declarations for OperationCreateTable.
std::mutex m_mutex
Mutex for serializing access to members
void decode_state_old(uint8_t version, const uint8_t **bufp, size_t *remainp) override
std::shared_ptr< Event > EventPtr
Smart pointer to Event.
Definition: Event.h:228
STL namespace.
EntityHeader header
Entity header
size_t encoded_length_vstr(size_t len)
Computes the encoded length of vstr (vint64, data, null)
OperationAlterTable(ContextPtr &context, const MetaLog::EntityHeader &header_)
Constructor for constructing object from MetaLog entry.
const char * get_text(int32_t state)
Definition: Operation.cc:609
const string & schema() const
Gets table schema.
Definition: AlterTable.h:68
A dynamic, resizable and reference counted memory buffer.
Definition: DynamicBuffer.h:42
Represents a set of table parts (sub-tables).
Definition: TableParts.h:47
uint32_t decode_i32(const uint8_t **bufp, size_t *remainp)
Decode a 32-bit integer in little-endian order.
bool get_schemas(SchemaPtr &original_schema, SchemaPtr &alter_schema)
Gets schema objects.
Declarations for ReferenceManager.
std::shared_ptr< Context > ContextPtr
Smart pointer to Context.
Definition: Context.h:265
Hyperspace definitions
virtual void dependencies(DependencySet &dependencies)
Definition: Operation.cc:464
TableParts m_parts
Index tables to be created or dropped.
void encode_state(uint8_t **bufp) const override
Writes serialized encoding of object state.
Open file for writing.
Definition: Session.h:73
virtual void encode(uint8_t **bufp) const
Writes serialized representation of object to a buffer.
Definition: Serializable.cc:64
void set_state(int32_t state)
Definition: Operation.h:473
bool decode_bool(const uint8_t **bufp, size_t *remainp)
Decodes a boolean value from the given buffer.
Definition: Serialization.h:96
const char * get_text(int error)
Returns a descriptive error message.
Definition: Error.cc:330
void add_dependency(const String &dependency)
Definition: Operation.h:462
const char * INIT
Definition: Operation.cc:45
void encode_i32(uint8_t **bufp, uint32_t val)
Encode a 32-bit integer in little-endian order.
Compatibility Macros for C/C++.
void stage_subop(std::shared_ptr< Operation > operation)
Stages a sub operation for execution.
Definition: Operation.cc:536
#define HT_END
Definition: Logger.h:220
Functions to serialize/deserialize primitives to/from a memory buffer.
void record_state()
Records operation state to the MML.
Definition: Operation.h:401
const string & name() const
Gets name of table to alter.
Definition: AlterTable.h:64
#define HT_ERROR_OUT
Definition: Logger.h:301
const char * METADATA
Definition: Operation.cc:48
Time related declarations.
virtual void decode(const uint8_t **bufp, size_t *remainp)
Reads serialized representation of object from a buffer.
Definition: Serializable.cc:70
void execute() override
Carries out the alter table operation.
void lock()
Locks the entity's mutex.
Definition: MetaLogEntity.h:97
void encode_vstr(uint8_t **bufp, const void *buf, size_t len)
Encode a buffer as variable length string (vint64, data, null)
Hypertable definitions
static Schema * new_instance(const std::string &buf)
Creates schema object from XML schema string.
Definition: Schema.cc:202
#define HT_FATALF(msg,...)
Definition: Logger.h:343
long long int Lld
Shortcut for printf formats.
Definition: String.h:53
Declarations for general-purpose utility functions.
TableParts get_drop_index_parts(SchemaPtr &original_schema, SchemaPtr &alter_schema)
Determines which index tables to drop.
const bool ON
Constant representing on
String m_schema
Schema for the table
DependencySet m_dependencies
Set of dependencies.
Definition: Operation.h:595
#define HT_INFOF(msg,...)
Definition: Logger.h:272
size_t encoded_length_state() const override
Returns serialized state length.
atomically open and lock file exclusive, fail if can't
Definition: Session.h:85
#define HT_THROWF(_code_, _fmt_,...)
Definition: Error.h:490
uint8_t * base
Pointer to the allocated memory buffer.
bool value_index() const
Test if value index is included in set.
Definition: TableParts.h:75
void get_table_server_set(ContextPtr &context, const String &id, const String &row, StringSet &servers)
Gets set of servers holding ranges for a given table.
Definition: Utility.cc:57
Abstract base class for master operations.
Definition: Operation.h:124
This is a generic exception class for Hypertable.
Definition: Error.h:314
void display_state(std::ostream &os) override
Writes human readable representation of object to output stream.
uint8_t encoding_version_state() const override
Returns encoding version.
DependencySet m_exclusivities
Set of exclusivities.
Definition: Operation.h:592
std::shared_ptr< Schema > SchemaPtr
Smart pointer to Schema.
Definition: Schema.h:465
const String name() override
Returns name of operation ("OperationAlterTable")
std::set< String > DependencySet
Set of dependency string.
Definition: Operation.h:107
StringSet m_completed
Set of range servers that have completed operation.
#define HT_MAYBE_FAIL(_label_)
void complete_ok(std::vector< MetaLog::EntityPtr > &additional)
Definition: Operation.cc:436
Declarations for OperationAlterTable.
Open file for reading.
Definition: Session.h:71
uint8_t decode_byte(const uint8_t **bufp, size_t *remainp)
Decodes a single byte from the given buffer.
Definition: Serialization.h:73
Error codes, Exception handling, error logging.
Lib::Master::Request::Parameters::AlterTable m_params
Request parmaeters.
const String label() override
Returns descriptive label for operation.
void complete_error(int error, const String &msg, std::vector< MetaLog::EntityPtr > &additional)
Completes operation with error.
Definition: Operation.cc:400
void decode_state(uint8_t version, const uint8_t **bufp, size_t *remainp) override
Reads serialized encoding of object state.
std::shared_ptr< DispatchHandlerOperation > DispatchHandlerOperationPtr
Smart pointer to DispatchHandlerOperation.
int64_t get_ts64()
Returns the current time in nanoseconds as a 64bit number.
Definition: Time.cc:40
int code() const
Returns the error code.
Definition: Error.h:391
Declarations for TableParts.
Executes user-defined functions when leaving the current scope.
StringSet m_servers
Set of participating range servers.
bool qualifier_index() const
Test if qualifier index is included in set.
Definition: TableParts.h:80