0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
check_integrity.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; either version 3
9  * of the 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 
22 #include <Common/Compat.h>
23 
24 #include <Hypertable/Lib/Config.h>
25 #include <Hypertable/Lib/Client.h>
27 
28 #include <Common/Config.h>
29 #include <Common/Error.h>
30 #include <Common/InetAddr.h>
31 #include <Common/Logger.h>
32 #include <Common/Init.h>
33 #include <Common/Timer.h>
34 #include <Common/Usage.h>
35 
36 #include <boost/progress.hpp>
37 #include <boost/algorithm/string.hpp>
38 
39 #include <chrono>
40 #include <cstdlib>
41 #include <iostream>
42 #include <mutex>
43 #include <thread>
44 
45 extern "C" {
46 #include <netdb.h>
47 #include <sys/types.h>
48 #include <signal.h>
49 }
50 
51 using namespace Hypertable;
52 using namespace Config;
53 using namespace std;
54 
55 namespace {
56 
57  const char *usage =
58  "Usage: check_integrity [options]\n\n"
59  "Description:\n"
60  " This program checks the integrity of the cluster by scanning all \n"
61  " available ranges of all tables.\n"
62  "\n"
63  "Options\n"
64  " sleep: specifies a sleep time (in seconds) during the requests to\n"
65  " reduce the load that is caused by this tool.\n";
66 
67  struct AppPolicy : Config::Policy {
68  static void init_options() {
69  cmdline_desc(usage).add_options()
70  ("sleep", i32()->default_value(0),
71  "Time to sleep between each request (in milliseconds)")
72  ("timeout", i32()->default_value(0),
73  "Hypertable connection timeout (in milliseconds)")
74  ;
75  }
76 
77  static void init() {
78  // we want to override the default behavior that verbose
79  // turns on debugging by clearing the defaulted flag
80  if (defaulted("logging-level"))
81  properties->set("logging-level", String("fatal"));
82  }
83  };
84 
85  typedef Meta::list<AppPolicy, FsClientPolicy, HyperspaceClientPolicy,
87  Policies;
88 
89 } // global namespace
90 
91 struct RangeInfo
92 {
95 };
96 
97 typedef std::vector<RangeInfo> RangeInfoVec;
98 
99 std::vector<String> errors;
101 
102 void add_error(const String &msg)
103 {
104  cout << msg << endl;
105  lock_guard<mutex> lock(error_mutex);
106  errors.push_back(msg);
107 }
108 
110 {
111  public:
113  const String &location, boost::progress_display *progress,
114  const RangeInfoVec &ranges, uint32_t sleep_ms)
115  : m_namespace(ns), m_namemap(namemap), m_ranges(ranges),
116  m_progress(progress), m_sleep_ms(sleep_ms) {
117  }
118 
119  void operator()() {
120  TablePtr table;
121 
122  for (size_t i = 0; i < m_ranges.size(); i++) {
123  String previous_table;
124  String previous_end;
125  String table_name;
126 
127  if (!m_namemap->id_to_name(m_ranges[i].tableid, table_name)) {
128  add_error(format("Table id %s is unknown, skipping table",
129  m_ranges[i].tableid.c_str()));
130  continue;
131  }
132 
133  if (table_name != previous_table) {
134  previous_table = table_name;
135  previous_end = "";
136  table = m_namespace->open_table(table_name);
137  }
138 
139  ScanSpecBuilder ssb;
140  ssb.set_cell_limit(1);
141 
142  // if the table has only one range then just create a scanner
143  // without any row interval
144  if (previous_end.empty() && m_ranges[i].endrow == "\xff\xff") {
145  // nop
146  }
147  // otherwise if this range is a normal range then query the end row
148  else if (m_ranges[i].endrow != "\xff\xff") {
149  ssb.add_row_interval(m_ranges[i].endrow.c_str(), true,
150  m_ranges[i].endrow.c_str(), true);
151  }
152  // otherwise if this range is the last range of a table then use
153  // the previous end row as the start row
154  else {
155  HT_ASSERT(previous_end.size());
156  HT_ASSERT(m_ranges[i].endrow == "\xff\xff");
157  ssb.add_row_interval(previous_end.c_str(), false,
158  m_ranges[i].endrow.c_str(), true);
159  }
160 
161  TableScanner *scanner = table->create_scanner(ssb.get(), 0);
162  Cell cell;
163  bool found = false;
164  while (scanner->next(cell))
165  found = true;
166  delete scanner;
167 
168  (*m_progress) += 1;
169  // ignore error if the table is empty
170  if (!found
171  && (previous_end != ""
172  || m_ranges[i].endrow != "\xff\xff")) {
173  add_error(format("Table %s: Range [%s..%s] was not found",
174  table_name.c_str(), previous_end.c_str(),
175  m_ranges[i].endrow.c_str()));
176  continue;
177  }
178  if (m_sleep_ms)
179  this_thread::sleep_for(chrono::milliseconds(m_sleep_ms));
180 
181  previous_end = m_ranges[i].endrow;
182  }
183  };
184 
185  private:
186  NamespacePtr m_namespace;
188  RangeInfoVec m_ranges;
189  boost::progress_display *m_progress;
190  uint32_t m_sleep_ms;
191 };
192 
193 int main(int argc, char **argv) {
194  typedef std::map<String, RangeInfoVec> RangeMap;
195  RangeMap ranges;
196  try {
197  init_with_policies<Policies>(argc, argv);
198 
199  uint32_t sleep_ms = get_i32("sleep");
200  uint32_t timeout_ms = get_i32("timeout");
201  String config = get("config", String(""));
202 
203  // connect to the server
204  Client *client = new Hypertable::Client(config, timeout_ms);
205  NamespacePtr ns = client->open_namespace("/");
206  TablePtr metatable = ns->open_table("sys/METADATA");
207 
208  // get a list of all ranges and their locations
209  int total_ranges = 0;
210  ScanSpecBuilder ssb;
211  ssb.set_max_versions(1);
212  ssb.add_column("Location");
213  TableScanner *scanner = metatable->create_scanner(ssb.get(), timeout_ms);
214  Cell cell;
215  while (scanner->next(cell)) {
216  char *endrow = strstr((char *)cell.row_key, ":");
217  *endrow++ = 0;
218  String location((const char *)cell.value,
219  (const char *)cell.value + cell.value_len);
220  //cout << cell.row_key << " " << endrow << "\t" << location << endl;
221 
222  RangeInfo ri;
223  ri.tableid = cell.row_key;
224  ri.endrow = endrow;
225  ranges[location].push_back(ri);
226 
227  total_ranges++;
228  }
229  delete scanner;
230 
231  // initialize a boost progress bar
232  cout << "Checking " << total_ranges << " ranges... please wait..." << endl;
233  boost::progress_display progress(total_ranges);
234 
235  // for each location: start a thread which will check the ranges
236  boost::thread_group threads;
237  for (RangeMap::iterator it = ranges.begin(); it != ranges.end(); ++it)
238  threads.create_thread(LocationThread(ns, client->get_nameid_mapper(),
239  it->first, &progress, it->second, sleep_ms));
240 
241  // then wait for the threads to join
242  threads.join_all();
243  }
244  catch (Exception &e) {
245  HT_ERROR_OUT << e << HT_END;
246  add_error(format("Exception caught: %s (%d)", Error::get_text(e.code()),
247  e.code()));
248  }
249 
250  if (errors.size()) {
251  cout << endl << endl << "Got " << errors.size() << " errors: " << endl;
252  for (const auto &s : errors)
253  cout << " " << s << endl;
254  }
255  else
256  cout << "Success - all ranges are available." << endl;
257 
258  quick_exit(errors.size()); // ditto
259 }
LocationThread(NamespacePtr &ns, NameIdMapperPtr namemap, const String &location, boost::progress_display *progress, const RangeInfoVec &ranges, uint32_t sleep_ms)
static std::mutex mutex
Definition: Logger.cc:43
NameIdMapperPtr get_nameid_mapper()
Definition: Client.cc:180
Interface and base of config policy.
Definition: Config.h:149
ScanSpec & get()
Returns the built ScanSpec object.
Definition: ScanSpec.h:566
NamespacePtr open_namespace(const std::string &name, Namespace *base=NULL)
Opens a Namespace.
Definition: Client.cc:106
NameIdMapperPtr m_namemap
PropertiesPtr properties
This singleton map stores all options.
Definition: Config.cc:47
std::string String
A String is simply a typedef to std::string.
Definition: String.h:44
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
std::vector< RangeInfo > RangeInfoVec
Helper class for printing usage banners on the command line.
void init(int argc, char *argv[], const Desc *desc=NULL)
Initialize with default policy.
Definition: Init.h:95
String tableid
std::vector< String > errors
STL namespace.
boost::progress_display * m_progress
Desc & cmdline_desc(const char *usage)
A macro which definds global functions like get_bool(), get_str(), get_i16() etc. ...
Definition: Config.cc:72
std::shared_ptr< Namespace > NamespacePtr
Shared smart pointer to Namespace.
Definition: Namespace.h:333
#define HT_ASSERT(_e_)
Definition: Logger.h:396
void set_cell_limit(int32_t n)
Sets the maximum number of cells to return.
Definition: ScanSpec.h:349
const char * get_text(int error)
Returns a descriptive error message.
Definition: Error.cc:330
Po::typed_value< int32_t > * i32(int32_t *v=0)
Definition: Properties.h:178
Helpers to compose init policies; allow to combine two policies into one.
Definition: Config.h:174
A timer class to keep timeout states across AsyncComm related calls.
Logging routines and macros.
bool next(Cell &cell)
Gets the next cell.
Definition: TableScanner.cc:49
Compatibility Macros for C/C++.
const char * row_key
Definition: Cell.h:66
Initialization helper for applications.
#define HT_END
Definition: Logger.h:220
Helper class for building a ScanSpec.
Definition: ScanSpec.h:318
bool defaulted(const String &name)
Check if a configuration value is defaulted.
Definition: Config.h:67
Synchronous table scanner.
Definition: TableScanner.h:39
#define HT_ERROR_OUT
Definition: Logger.h:301
Holds pointer to range and cached start and end rows.
Definition: TableInfo.h:94
Hypertable definitions
void add_column(const string &str)
Adds a column family to be returned by the scan.
Definition: ScanSpec.h:408
void add_row_interval(const string &start, bool start_inclusive, const string &end, bool end_inclusive)
Adds a row interval to be returned in the scan.
Definition: ScanSpec.h:455
Internet address wrapper classes and utility functions.
Meta::list< MyPolicy, DefaultPolicy > Policies
void add_error(const String &msg)
This is a generic exception class for Hypertable.
Definition: Error.h:314
std::mutex error_mutex
uint32_t value_len
Definition: Cell.h:72
Configuration settings.
int main(int argc, char **argv)
Encapsulates decomposed key and value.
Definition: Cell.h:32
void set_max_versions(uint32_t n)
Sets the maximum number of revisions of each cell to return in the scan.
Definition: ScanSpec.h:387
std::shared_ptr< NameIdMapper > NameIdMapperPtr
Smart pointer to NameIdMapper.
Definition: NameIdMapper.h:121
Error codes, Exception handling, error logging.
std::shared_ptr< Table > TablePtr
Definition: Table.h:53
const uint8_t * value
Definition: Cell.h:71
int code() const
Returns the error code.
Definition: Error.h:391
RangeInfoVec m_ranges