0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Namespace.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 
22 #include <Common/Compat.h>
23 
24 #include "Client.h"
25 #include "HqlCommandInterpreter.h"
26 
27 #include <Hyperspace/DirEntry.h>
28 #include <Hypertable/Lib/Config.h>
30 
31 #include <AsyncComm/Comm.h>
33 
34 #include <Common/Init.h>
35 #include <Common/Error.h>
36 #include <Common/InetAddr.h>
37 #include <Common/Logger.h>
38 #include <Common/ScopeGuard.h>
39 #include <Common/StringExt.h>
40 #include <Common/System.h>
41 #include <Common/Timer.h>
42 
43 #include <boost/algorithm/string.hpp>
44 
45 #include <cassert>
46 #include <cstdlib>
47 #include <memory>
48 #include <mutex>
49 
50 using namespace std;
51 using namespace Hypertable;
52 using namespace Hyperspace;
53 using namespace Config;
54 
55 Namespace::Namespace(const string &name, const string &id, PropertiesPtr &props,
56  ConnectionManagerPtr &conn_manager, Hyperspace::SessionPtr &hyperspace,
57  ApplicationQueueInterfacePtr &app_queue, NameIdMapperPtr &namemap, Lib::Master::ClientPtr &master_client,
58  RangeLocatorPtr &range_locator, TableCachePtr &table_cache,
59  uint32_t timeout, Client *client)
60  : m_name(name), m_id(id), m_props(props),
61  m_comm(conn_manager->get_comm()), m_conn_manager(conn_manager), m_hyperspace(hyperspace),
62  m_app_queue(app_queue), m_namemap(namemap), m_master_client(master_client),
63  m_range_locator(range_locator), m_table_cache(table_cache),
64  m_timeout_ms(timeout), m_client(client) {
65 
66  HT_ASSERT(m_props && conn_manager && m_hyperspace && m_app_queue && m_namemap &&
68 
69  m_hyperspace_reconnect = m_props->get_bool("Hyperspace.Session.Reconnect");
70  m_toplevel_dir = m_props->get_str("Hypertable.Directory");
73 }
74 
75 String Namespace::get_full_name(const string &sub_name) {
76  // remove leading/trailing '/' and ' '
77  string full_name = sub_name;
78  boost::trim_if(full_name, boost::is_any_of("/ "));
79  full_name = m_name + '/' + full_name;
80  canonicalize(&full_name);
81  return full_name;
82 }
83 
85  string output;
86  boost::char_separator<char> sep("/");
87 
88  if (original == NULL)
89  return;
90 
91  Tokenizer tokens(*original, sep);
92  for (Tokenizer::iterator tok_iter = tokens.begin();
93  tok_iter != tokens.end(); ++tok_iter)
94  if (tok_iter->size() > 0)
95  output += *tok_iter + "/";
96 
97  // remove leading/trailing '/' and ' '
98  boost::trim_if(output, boost::is_any_of("/ "));
99  *original = output;
100 }
101 
102 void Namespace::compact(const string &name, const string &row, uint32_t flags) {
103  if (name.empty())
104  m_master_client->compact("", "", flags);
105  else {
106  string full_name = get_full_name(name);
107  m_master_client->compact(full_name, row, flags);
108  }
109 }
110 
111 void Namespace::create_table(const string &table_name, const string &schema_str) {
112  string name = Filesystem::basename(table_name);
113  if (name.size() && name[0]=='^')
114  HT_THROW(Error::SYNTAX_ERROR, (String)"Invalid table name character '^'");
115 
116  // Parse and validate schema
117  SchemaPtr schema( Schema::new_instance(schema_str) );
118 
119  string full_name = get_full_name(table_name);
120  m_master_client->create_table(full_name, schema_str);
121 }
122 
123 void
124 Namespace::create_table(const string &table_name, SchemaPtr &schema) {
125  string name = Filesystem::basename(table_name);
126  if (name.size() && name[0]=='^')
127  HT_THROW(Error::SYNTAX_ERROR, (String)"Invalid table name character '^'");
128 
129  const string schema_str = schema->render_xml(true);
130  string full_name = get_full_name(table_name);
131  m_master_client->create_table(full_name, schema_str);
132 }
133 
134 
135 void Namespace::alter_table(const string &table_name, SchemaPtr &schema, bool force) {
136  string name = Filesystem::basename(table_name);
137  if (name.size() && name[0]=='^')
138  HT_THROW(Error::SYNTAX_ERROR, (String)"Invalid table name character '^'");
139  string full_name = get_full_name(table_name);
140  const string schema_str = schema->render_xml(true);
141  m_master_client->alter_table(full_name, schema_str, force);
142 }
143 
144 
145 void Namespace::alter_table(const string &table_name, const string &schema_str, bool force) {
146  string name = Filesystem::basename(table_name);
147  if (name.size() && name[0]=='^')
148  HT_THROW(Error::SYNTAX_ERROR, (String)"Invalid table name character '^'");
149  string full_name = get_full_name(table_name);
150  SchemaPtr schema( Schema::new_instance(schema_str) );
151  m_master_client->alter_table(full_name, schema_str, force);
152 }
153 
154 
155 TablePtr Namespace::open_table(const string &table_name, int32_t flags) {
156  lock_guard<TableCache> lock(*m_table_cache);
157  string full_name = get_full_name(table_name);
158  TablePtr table = _open_table(full_name, flags);
159 
160  if (table->needs_index_table() && !table->has_index_table()) {
161  full_name = get_full_name( get_index_table_name(table_name) );
162  table->set_index_table(_open_table(full_name, 0));
163  }
164 
165  if (table->needs_qualifier_index_table()
166  && !table->has_qualifier_index_table()) {
167  full_name = get_full_name( get_qualifier_index_table_name(table_name) );
168  table->set_qualifier_index_table(_open_table(full_name, 0));
169  }
170 
171  return table;
172 }
173 
174 TablePtr Namespace::_open_table(const string &full_name, int32_t flags) {
175  TablePtr t;
177  t = make_shared<Table>(m_props, m_range_locator, m_conn_manager, m_hyperspace,
178  m_app_queue, m_namemap, full_name, flags, m_timeout_ms);
179  else
180  t=m_table_cache->get_unlocked(full_name, flags);
181  t->set_namespace(this);
182  return (t);
183 }
184 
185 void Namespace::refresh_table(const string &table_name) {
187 }
188 
189 bool Namespace::exists_table(const string &table_name) {
190  string full_name = get_full_name(table_name);
191 
192  string table_id;
193  bool is_namespace = false;
194 
195  if (!m_namemap->name_to_id(full_name, table_id, &is_namespace) ||
196  is_namespace)
197  return false;
198 
199  // TODO: issue 11
200 
201  string table_file = m_toplevel_dir + "/tables/" + table_id;
202 
203  try {
204  if (!m_hyperspace->attr_exists(table_file, "x"))
205  return false;
206  }
207  catch(Exception &e) {
210  return false;
211  HT_THROW(e.code(), e.what());
212  }
213  return true;
214 }
215 
216 
217 String Namespace::get_table_id(const string &table_name) {
218  string full_name = get_full_name(table_name);
219  string table_id;
220  bool is_namespace;
221 
222  if (!m_namemap->name_to_id(full_name, table_id, &is_namespace) ||
223  is_namespace)
224  HT_THROW(Error::TABLE_NOT_FOUND, full_name);
225  return table_id;
226 }
227 
228 String Namespace::get_schema_str(const string &table_name, bool with_ids) {
229  string schema;
230  string full_name = get_full_name(table_name);
231 
232  refresh_table(table_name);
233  if (!m_table_cache->get_schema_str(full_name, schema, with_ids))
234  HT_THROW(Error::TABLE_NOT_FOUND, full_name);
235  return schema;
236 }
237 
238 SchemaPtr Namespace::get_schema(const string &table_name) {
239  SchemaPtr schema;
240  string full_name = get_full_name(table_name);
241 
242  refresh_table(table_name);
243  if (!m_table_cache->get_schema(full_name, schema))
244  HT_THROW(Error::TABLE_NOT_FOUND, full_name);
245  return schema;
246 }
247 
248 void Namespace::rename_table(const string &old_name, const string &new_name) {
249  string name = Filesystem::basename(old_name);
250  if (name.size() && name[0]=='^')
251  HT_THROW(Error::SYNTAX_ERROR, (String)"Invalid table name character '^'");
252  name = Filesystem::basename(new_name);
253  if (name.size() && name[0]=='^')
254  HT_THROW(Error::SYNTAX_ERROR, (String)"Invalid table name character '^'");
255  string full_old_name = get_full_name(old_name);
256  string full_new_name = get_full_name(new_name);
257 
258  m_master_client->rename_table(full_old_name, full_new_name);
259 
260  m_table_cache->remove(full_old_name);
261 
262  // also remove the index table from the cache
263  string index_name=get_index_table_name(old_name);
264  m_table_cache->remove(get_full_name(index_name));
265  index_name=get_qualifier_index_table_name(old_name);
266  m_table_cache->remove(get_full_name(index_name));
267 }
268 
269 void Namespace::drop_table(const string &table_name, bool if_exists) {
270  string name = Filesystem::basename(table_name);
271  if (name.size() && name[0]=='^')
272  HT_THROW(Error::SYNTAX_ERROR, (String)"Invalid table name character '^'");
273 
274  string full_name = get_full_name(table_name);
275 
276  m_master_client->drop_table(full_name, if_exists);
277  m_table_cache->remove(full_name);
278 
279  // also remove the index tables from the cache
280  string index_name=get_index_table_name(table_name);
281  m_table_cache->remove(get_full_name(index_name));
282  index_name=get_qualifier_index_table_name(table_name);
283  m_table_cache->remove(get_full_name(index_name));
284 }
285 
286 void Namespace::rebuild_indices(const std::string &table_name,
287  TableParts table_parts) {
288 
289  string full_name = get_full_name(table_name);
290 
291  m_master_client->recreate_index_tables(full_name, table_parts);
292 
293  // Rebuild indices
294  {
295  TablePtr table = open_table(table_name);
296  ScanSpec scan_spec;
297  scan_spec.rebuild_indices = table_parts;
298  TableScannerPtr scanner( table->create_scanner(scan_spec) );
299  Cell cell;
300  while (scanner->next(cell))
301  HT_ASSERT(!"Rebuild index scan returned a cell");
302  }
303 
304  // also remove the index tables from the cache
305  string index_name=get_index_table_name(table_name);
306  m_table_cache->remove(get_full_name(index_name));
307  index_name=get_qualifier_index_table_name(table_name);
308  m_table_cache->remove(get_full_name(index_name));
309 }
310 
311 void Namespace::get_listing(bool include_sub_entries, std::vector<NamespaceListing> &listing) {
312  m_namemap->id_to_sublisting(m_id, include_sub_entries, listing);
313 }
314 
315 
316 void Namespace::get_table_splits(const string &table_name, TableSplitsContainer &splits) {
317  TablePtr table;
319  SchemaPtr schema;
320  ScanSpec scan_spec;
321  Cell cell;
322  string str;
324  string last_row;
325  TableSplitBuilder tsbuilder(splits.arena());
326  ProxyMapT proxy_map;
327  string full_name = get_full_name(table_name);
328 
329  try_again:
330 
331  table = open_table(table_name);
332 
333  table->get(tid, schema);
334 
335  {
336  lock_guard<TableCache> lock(*m_table_cache);
338  }
339 
340  size_t rowlen = strlen(tid.id)+2;
341  std::shared_ptr<char> start_row( new char[rowlen], []( char *p ) { delete[] p; } );
342  std::shared_ptr<char> end_row( new char[rowlen+strlen(Key::END_ROW_MARKER)], []( char *p ) { delete[] p; } );
343 
344  sprintf(start_row.get(), "%s:", tid.id);
345  sprintf(end_row.get(), "%s:%s", tid.id, Key::END_ROW_MARKER);
346 
347  scan_spec.clear();
348  scan_spec.row_limit = 0;
349  scan_spec.max_versions = 1;
350  scan_spec.columns.clear();
351  scan_spec.columns.push_back("Location");
352  scan_spec.columns.push_back("StartRow");
353 
354  ri.start = start_row.get();
355  ri.end = end_row.get();
356  scan_spec.row_intervals.push_back(ri);
357 
358  TableScannerPtr scanner_ptr( table->create_scanner(scan_spec) );
359 
360  m_comm->get_proxy_map(proxy_map);
361 
362  bool refresh=true;
363  tsbuilder.clear();
364  splits.clear();
365  last_row.clear();
366  while (scanner_ptr->next(cell)) {
367  refresh = false;
368  if (strcmp(last_row.c_str(), cell.row_key) && last_row != "") {
369  const char *ptr = strchr(last_row.c_str(), ':');
370  HT_ASSERT(ptr);
371  tsbuilder.set_end_row(ptr+1);
372  splits.push_back(tsbuilder.get());
373  tsbuilder.clear();
374  }
375  if (!strcmp(cell.column_family, "Location")) {
376  str = String((const char *)cell.value, cell.value_len);
377  if (str == "!") {
378  refresh = true;
379  break;
380  }
381  boost::trim(str);
382  tsbuilder.set_location(str);
383  ProxyMapT::iterator pmiter = proxy_map.find(str);
384  if (pmiter != proxy_map.end()) {
385  tsbuilder.set_ip_address( (*pmiter).second.addr.format_ipaddress() );
386  tsbuilder.set_hostname( (*pmiter).second.hostname );
387  }
388  }
389  else if (!strcmp(cell.column_family, "StartRow")) {
390  str = String((const char *)cell.value, cell.value_len);
391  boost::trim(str);
392  tsbuilder.set_start_row(str);
393  }
394  else
395  HT_FATALF("Unexpected column family - %s", cell.column_family);
396  last_row = cell.row_key;
397  }
398  if (refresh) {
399  refresh_table(table_name);
400  goto try_again;
401  }
402  tsbuilder.set_end_row(Key::END_ROW_MARKER);
403  splits.push_back(tsbuilder.get());
404 }
std::string get_qualifier_index_table_name(const std::string &table_name)
Definition: Namespace.h:302
Retrieves system information (hardware, installation directory, etc)
std::string get_index_table_name(const std::string &table_name)
Definition: Namespace.h:297
void get_table_splits(const std::string &name, TableSplitsContainer &splits)
Returns a list of existing table names.
Definition: Namespace.cc:316
TableCachePtr m_table_cache
Definition: Namespace.h:327
TablePtr open_table(const std::string &name, int32_t flags=0)
Opens a table.
Definition: Namespace.cc:155
std::string String
A String is simply a typedef to std::string.
Definition: String.h:44
std::shared_ptr< RangeLocator > RangeLocatorPtr
Smart pointer to RangeLocator.
Definition: RangeLocator.h:198
ApplicationQueueInterfacePtr m_app_queue
Definition: Namespace.h:321
static const char * METADATA_NAME
Declarations for TableIdentifier and TableIdentifierManaged.
Po::typed_value< String > * str(String *v=0)
Definition: Properties.h:166
Lib::Master::ClientPtr m_master_client
Definition: Namespace.h:323
void rebuild_indices(const std::string &table_name, TableParts table_parts)
Rebuild a table's indices.
Definition: Namespace.cc:286
STL namespace.
void compact(const std::string &name, const std::string &row, uint32_t flags)
Performs a manual compaction.
Definition: Namespace.cc:102
std::string get_table_id(const std::string &name)
Returns the table identifier for a table.
Definition: Namespace.cc:217
static void canonicalize(String *original)
Get canonical format of name/id string.
Definition: Namespace.cc:84
ConnectionManagerPtr m_conn_manager
Definition: Namespace.h:319
std::shared_ptr< TableScanner > TableScannerPtr
Smart pointer to TableScanner.
Definition: TableScanner.h:124
Represents a set of table parts (sub-tables).
Definition: TableParts.h:47
TablePtr _open_table(const std::string &full_name, int32_t flags=0)
Definition: Namespace.cc:174
Represents a row interval.
Definition: RowInterval.h:38
Hyperspace definitions
std::shared_ptr< Client > ClientPtr
Definition: Client.h:156
#define HT_ASSERT(_e_)
Definition: Logger.h:396
Wrapper for TableIdentifier providing member storage.
Scan predicate and control specification.
Definition: ScanSpec.h:56
std::string get_full_name(const std::string &sub_name)
Definition: Namespace.cc:75
std::shared_ptr< Session > SessionPtr
Definition: Session.h:734
void get_listing(bool include_sub_entries, std::vector< NamespaceListing > &listing)
Returns a list of existing tables & namesspaces.
Definition: Namespace.cc:311
void create_table(const std::string &name, const std::string &schema_str)
Creates a table.
Definition: Namespace.cc:111
std::string m_name
Definition: Namespace.h:315
SchemaPtr get_schema(const std::string &name)
Returns a smart ptr to a schema object for a table.
Definition: Namespace.cc:238
std::shared_ptr< Properties > PropertiesPtr
Definition: Properties.h:447
TableParts rebuild_indices
Definition: ScanSpec.h:286
A timer class to keep timeout states across AsyncComm related calls.
std::string m_toplevel_dir
Definition: Namespace.h:325
Logging routines and macros.
std::unordered_map< String, ProxyAddressInfo > ProxyMapT
Forward mapping hash type from proxy name to ProxyAddressInfo.
Definition: ProxyMap.h:57
Compatibility Macros for C/C++.
const char * row_key
Definition: Cell.h:66
Initialization helper for applications.
std::shared_ptr< ApplicationQueueInterface > ApplicationQueueInterfacePtr
Smart pointer to ApplicationQueueInterface.
static String basename(String name, char separator= '/')
A posix-compliant basename() which strips directory names from a filename.
Definition: Filesystem.cc:154
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
std::shared_ptr< TableCache > TableCachePtr
Smart pointer to TableCache.
Definition: TableCache.h:103
Declarations for HqlCommandInterpreter.
PropertiesPtr m_props
Definition: Namespace.h:317
void get_proxy_map(ProxyMapT &proxy_map)
Returns the proxy map.
Definition: Comm.cc:231
void alter_table(const std::string &table_name, SchemaPtr &schema, bool force)
Alter table schema.
Definition: Namespace.cc:135
bool exists_table(const std::string &name)
Checks if the table exists.
Definition: Namespace.cc:189
Declarations for Comm.
const char * column_family
Definition: Cell.h:67
boost::tokenizer< boost::char_separator< char > > Tokenizer
Definition: Namespace.h:309
Internet address wrapper classes and utility functions.
RowIntervals row_intervals
Definition: ScanSpec.h:275
std::string get_schema_str(const std::string &name, bool with_ids=false)
Returns the schema for a table.
Definition: Namespace.cc:228
Declarations for ReactorFactory.
This is a generic exception class for Hypertable.
Definition: Error.h:314
void rename_table(const std::string &old_name, const std::string &new_name)
Renames a table.
Definition: Namespace.cc:248
NameIdMapperPtr m_namemap
Definition: Namespace.h:322
uint32_t value_len
Definition: Cell.h:72
std::shared_ptr< Schema > SchemaPtr
Smart pointer to Schema.
Definition: Schema.h:465
std::string m_id
Definition: Namespace.h:316
RangeLocatorPtr m_range_locator
Definition: Namespace.h:324
std::shared_ptr< ConnectionManager > ConnectionManagerPtr
Smart pointer to ConnectionManager.
Hyperspace::SessionPtr m_hyperspace
Definition: Namespace.h:320
Encapsulates decomposed key and value.
Definition: Cell.h:32
String extensions and helpers: sets, maps, append operators etc.
void drop_table(const std::string &name, bool if_exists)
Removes a table.
Definition: Namespace.cc:269
std::shared_ptr< NameIdMapper > NameIdMapperPtr
Smart pointer to NameIdMapper.
Definition: NameIdMapper.h:121
Error codes, Exception handling, error logging.
#define HT_THROW(_code_, _msg_)
Definition: Error.h:478
static const char * END_ROW_MARKER
Definition: Key.h:49
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
void refresh_table(const std::string &name)
Refreshes the cached table entry.
Definition: Namespace.cc:185
Executes user-defined functions when leaving the current scope.