0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
AccessGroupHintsFile.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 
29 #include <Common/Compat.h>
30 
31 #include "AccessGroupHintsFile.h"
32 #include "Global.h"
33 
35 
36 #include <Common/DynamicBuffer.h>
37 #include <Common/Error.h>
38 #include <Common/Logger.h>
39 #include <Common/StaticBuffer.h>
40 #include <Common/String.h>
41 #include <Common/md5.h>
42 
43 #include <boost/tokenizer.hpp>
44 
45 #define HINTS_FILE_VERSION 3
46 
47 using namespace Hypertable;
48 
50  const String &start_row,
51  const String &end_row) :
52  m_table_id(table) {
53  change_start_row(start_row);
54  change_end_row(end_row);
55 }
56 
58  LoadDataEscape escaper;
59  escaper.escape(start_row.c_str(), start_row.length(), m_start_row);
60 }
61 
63  LoadDataEscape escaper;
64  char md5DigestStr[33];
65  md5_trunc_modified_base64(end_row.c_str(), md5DigestStr);
66  md5DigestStr[16] = 0;
67  m_range_dir = md5DigestStr;
68  escaper.escape(end_row.c_str(), end_row.length(), m_end_row);
69 }
70 
71 namespace {
72  const char *ag_hint_format = " %s: {\n"
73  " LatestStoredRevision: %lld,\n"
74  " DiskUsage: %llu,\n"
75  " Files: %s\n }\n";
76 }
77 
79  int32_t fd = -1;
80  bool first_try = true;
81 
82  String parent_dir = format("%s/tables/%s/default/%s",
83  Global::toplevel_dir.c_str(),
84  m_table_id.c_str(), m_range_dir.c_str());
85 
86  if (location.empty())
87  location = "?";
88 
89  String contents =
90  format("Version: %d\nStart Row: %s\nEnd Row: %s\nLocation: %s\n"
91  "Access Groups: {\n", HINTS_FILE_VERSION, m_start_row.c_str(),
92  m_end_row.c_str(), location.c_str());
93  for (const auto &h : m_hints)
94  contents += format(ag_hint_format, h.ag_name.c_str(),
95  (Llu)h.latest_stored_revision,
96  (Lld)h.disk_usage, h.files.c_str());
97  contents += "}\n";
98 
99  try_again:
100 
101  try {
102  if (!first_try) {
103  if (fd != -1)
104  Global::dfs->close(fd);
105  if (!Global::dfs->exists(parent_dir))
106  Global::dfs->mkdirs(parent_dir);
107  }
108  fd = Global::dfs->create(parent_dir + "/hints",
109  Filesystem::OPEN_FLAG_OVERWRITE, -1, -1, -1);
110  StaticBuffer sbuf(contents.length());
111  memcpy(sbuf.base, contents.c_str(), contents.length());
112  Global::dfs->append(fd, sbuf);
113  Global::dfs->close(fd);
114  }
115  catch (Exception &e) {
116  HT_INFOF("Exception caught writing hints file %s/hints - %s",
117  parent_dir.c_str(), Error::get_text(e.code()));
118  if (first_try) {
119  first_try = false;
120  goto try_again;
121  }
122  HT_ERRORF("Problem writing hints file %s/hints - %s",
123  parent_dir.c_str(), Error::get_text(e.code()));
124  }
125 
126 }
127 
129  int32_t fd = -1;
131  DynamicBuffer dbuf;
132 
133  m_hints.clear();
134 
135  String filename = format("%s/tables/%s/default/%s/hints",
136  Global::toplevel_dir.c_str(),
137  m_table_id.c_str(), m_range_dir.c_str());
138  try {
139 
140  int64_t length = Global::dfs->length(filename);
141  const char *base;
142 
143  dbuf.grow(length+1);
144 
146  size_t nread = Global::dfs->read(fd, dbuf.base, length);
147  Global::dfs->close(fd);
148  dbuf.base[nread] = 0;
149 
150  parse_header((const char *)dbuf.base, &base);
151 
152  const char *ptr = base;
153 
154  h.clear();
155  while ((ptr = strchr(base, ':')) != 0) {
156  h.ag_name = String((const char *)base, ptr-base);
157  boost::trim(h.ag_name);
158  if (h.ag_name.empty())
160  base = ptr+1;
161  while (*base && isspace(*base))
162  base++;
163  if (*base == '{') {
164  base++;
165  ptr = strchr(base, '}');
166  if (ptr == 0)
168  String text = String(base, ptr-base);
169  boost::trim(text);
170  boost::char_separator<char> sep(",");
171  boost::tokenizer< boost::char_separator<char> > tokens(text, sep);
172  for (const auto &mapping : tokens) {
173  char *end;
174  const char *ptr2 = strchr(mapping.c_str(), ':');
175  if (ptr2 == 0)
177  String key = String(mapping, 0, ptr2-mapping.c_str());
178  boost::trim(key);
179  String value = String(mapping, (ptr2-mapping.c_str())+1);
180  boost::trim(value);
181  if (key.empty())
183  if (key == "LatestStoredRevision") {
184  h.latest_stored_revision = strtoll(value.c_str(), &end, 0);
185  if (value.empty() || *end != 0)
187  }
188  else if (key == "DiskUsage") {
189  h.disk_usage = strtoull(value.c_str(), &end, 0);
190  if (value.empty() || *end != 0)
192  }
193  else if (key == "Files")
194  h.files = value;
195  else {
196  HT_WARNF("Unrecognized key (%s) in hints file %s",
197  key.c_str(), filename.c_str());
198  }
199  }
200  m_hints.push_back(h);
201  h.clear();
202  base = ptr+1;
203  }
204  else
206  }
207  }
208  catch (Exception &e) {
209  HT_ERRORF("Problem loading hints file %s - %s", filename.c_str(),
210  Error::get_text(e.code()));
211  m_hints.clear();
212  }
213 }
214 
216 
217  string path = format("%s/tables/%s/default/%s", Global::toplevel_dir.c_str(),
218  m_table_id.c_str(), m_range_dir.c_str());
219 
220  if (!Global::dfs->exists(path))
221  return false;
222 
223  path.append("/hints");
224 
225  return Global::dfs->exists(path);
226 
227 }
228 
229 namespace {
230  const char *parse_key_value(const char *base, String &key,
231  const char **value, size_t *value_len) {
232  const char *ptr;
233 
234  if ((ptr = strchr(base, ':')) == 0)
236 
237  key = String((const char *)base, ptr-base);
238  boost::trim(key);
239  if (key.empty() || ptr[1] != ' ')
241  *value = ptr+2;
242  ptr += 2;
243  while (*ptr && *ptr != '\n')
244  ptr++;
245  if (*ptr != '\n')
247  *value_len = ptr - *value;
248  return ptr+1;
249  }
250 }
251 
252 
253 void AccessGroupHintsFile::parse_header(const char *input, const char **ag_base) {
254  const char *base = input;
255  String key;
256  const char *value;
257  size_t value_len;
258 
259  base = parse_key_value(base, key, &value, &value_len);
260 
261  // Check for old format that doesn't have header fields
262  if (key != "Version") {
263  *ag_base = input;
264  return;
265  }
266 
267  int version = atoi(value);
268  if (version > 3)
270  "Unrecognized hints file version (%d)", version);
271 
272  base = parse_key_value(base, key, &value, &value_len);
273  if (key != "Start Row")
275  "Unexpected key in hints file (%s)", key.c_str());
276 
277  base = parse_key_value(base, key, &value, &value_len);
278  if (key != "End Row")
280  "Unexpected key in hints file (%s)", key.c_str());
281 
282  if (version >= 3) {
283  base = parse_key_value(base, key, &value, &value_len);
284  if (key != "Location")
286  "Unexpected key in hints file (%s)", key.c_str());
287  }
288 
289  base = parse_key_value(base, key, &value, &value_len);
290  if (key != "Access Groups")
292  "Unexpected key in hints file (%s)", key.c_str());
293  *ag_base = base;
294 }
A memory buffer of static size.
Definition: StaticBuffer.h:45
void change_end_row(const String &end_row)
Changes the end row.
#define HT_WARNF(msg,...)
Definition: Logger.h:290
static String filename
Definition: Config.cc:48
void parse_header(const char *input, const char **ag_base)
Parses header portion of hints file.
AccessGroupHintsFile(const String &table, const String &start_row, const String &end_row)
Constructor.
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
long long unsigned int Llu
Shortcut for printf formats.
Definition: String.h:50
void change_start_row(const String &start_row)
Changes the start row.
bool escape(const char *in_buf, size_t in_len, const char **out_bufp, size_t *out_lenp)
A dynamic, resizable and reference counted memory buffer.
Definition: DynamicBuffer.h:42
void md5_trunc_modified_base64(const char *input, char output[17])
Get the modified base64 encoded string of the first 12 Bytes of the 16 Byte MD5 code of a null termin...
Definition: md5.cc:425
A dynamic, resizable memory buffer.
static std::string toplevel_dir
Definition: Global.h:108
const char * get_text(int error)
Returns a descriptive error message.
Definition: Error.cc:330
void grow(size_t new_size, bool nocopy=false)
Grows the buffer and copies the data unless nocopy is true.
Logging routines and macros.
bool exists()
Checks if hints file exists.
Compatibility Macros for C/C++.
Declarations for AccessGroupHintsFile.
std::vector< AccessGroup::Hints > m_hints
Vector of access group hints.
static Hypertable::FilesystemPtr dfs
Definition: Global.h:64
A memory buffer of static size.
Hypertable definitions
long long int Lld
Shortcut for printf formats.
Definition: String.h:53
void write(String location)
Write hints file.
#define HT_INFOF(msg,...)
Definition: Logger.h:272
#define HT_THROWF(_code_, _fmt_,...)
Definition: Error.h:490
uint8_t * base
Pointer to the allocated memory buffer.
This is a generic exception class for Hypertable.
Definition: Error.h:314
A String class based on std::string.
#define HT_ERRORF(msg,...)
Definition: Logger.h:300
#define HINTS_FILE_VERSION
Error codes, Exception handling, error logging.
#define HT_THROW(_code_, _msg_)
Definition: Error.h:478
md5 digest routines.
String m_range_dir
Range subdirectory (md5 of end row)
int code() const
Returns the error code.
Definition: Error.h:391