Skip to content

Commit f15198c

Browse files
authored
Implement examples for all APIs (#372)
This fixes #38.
1 parent 31921b5 commit f15198c

File tree

2 files changed

+331
-0
lines changed

2 files changed

+331
-0
lines changed

bigtable/examples/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@
1818

1919
add_executable(bigtable_hello_world bigtable_hello_world.cc)
2020
target_link_libraries(bigtable_hello_world bigtable_client)
21+
22+
add_executable(bigtable_samples bigtable_samples.cc)
23+
target_link_libraries(bigtable_samples bigtable_client)
Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
// Copyright 2018 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "bigtable/client/table.h"
16+
#include "bigtable/client/table_admin.h"
17+
#include <google/protobuf/text_format.h>
18+
#include <sstream>
19+
20+
namespace {
21+
22+
/**
23+
* The key used for ReadRow(), ReadModifyWrite(), CheckAndMutate.
24+
*
25+
* Using the same key makes it possible for the user to see the effect of
26+
* the different APIs on one row.
27+
*/
28+
const std::string MAGIC_ROW_KEY = "key-000009";
29+
30+
//! [create table]
31+
void CreateTable(bigtable::TableAdmin& admin, std::string const& table_id) try {
32+
auto schema = admin.CreateTable(
33+
table_id, bigtable::TableConfig(
34+
{{"fam", bigtable::GcRule::MaxNumVersions(10)},
35+
{"foo", bigtable::GcRule::MaxAge(std::chrono::hours(72))}},
36+
{}));
37+
} catch (std::exception const& ex) {
38+
std::cerr << "Ignoring exceptions raised by CreateTable(): " << ex.what()
39+
<< std::endl;
40+
}
41+
//! [create table]
42+
43+
//! [list tables]
44+
void ListTables(bigtable::TableAdmin& admin) {
45+
auto tables =
46+
admin.ListTables(google::bigtable::admin::v2::Table::SCHEMA_VIEW);
47+
for (auto const& table : tables) {
48+
std::cout << table.name() << std::endl;
49+
}
50+
}
51+
//! [list tables]
52+
53+
//! [get table]
54+
void GetTable(bigtable::TableAdmin& admin, std::string const& table_id) {
55+
auto table =
56+
admin.GetTable(table_id, google::bigtable::admin::v2::Table::FULL);
57+
std::cout << table.name() << "\n";
58+
for (auto const& family : table.column_families()) {
59+
std::string const& family_name = family.first;
60+
std::string gc_rule;
61+
google::protobuf::TextFormat::PrintToString(family.second.gc_rule(),
62+
&gc_rule);
63+
std::cout << "\t" << family_name << "\t\t" << gc_rule << std::endl;
64+
}
65+
}
66+
//! [get table]
67+
68+
//! [delete table]
69+
void DeleteTable(bigtable::TableAdmin& admin, std::string const& table_id) {
70+
admin.DeleteTable(table_id);
71+
}
72+
//! [delete table]
73+
74+
//! [modify table]
75+
void ModifyTable(bigtable::TableAdmin& admin, std::string const& table_id) {
76+
auto schema = admin.ModifyColumnFamilies(
77+
table_id,
78+
{bigtable::ColumnFamilyModification::Drop("foo"),
79+
bigtable::ColumnFamilyModification::Update(
80+
"fam", bigtable::GcRule::Union(
81+
bigtable::GcRule::MaxNumVersions(5),
82+
bigtable::GcRule::MaxAge(std::chrono::hours(24 * 7)))),
83+
bigtable::ColumnFamilyModification::Create(
84+
"bar", bigtable::GcRule::Intersection(
85+
bigtable::GcRule::MaxNumVersions(3),
86+
bigtable::GcRule::MaxAge(std::chrono::hours(72))))});
87+
88+
std::string formatted;
89+
google::protobuf::TextFormat::PrintToString(schema, &formatted);
90+
std::cout << "Schema modified to: " << formatted << std::endl;
91+
}
92+
//! [modify table]
93+
94+
//! [drop all rows]
95+
void DropAllRows(bigtable::TableAdmin& admin, std::string const& table_id) {
96+
admin.DropAllRows(table_id);
97+
}
98+
//! [drop all rows]
99+
100+
//! [drop rows by prefix]
101+
void DropRowsByPrefix(bigtable::TableAdmin& admin,
102+
std::string const& table_id) {
103+
admin.DropRowsByPrefix(table_id, "key-00004");
104+
}
105+
//! [drop rows by prefix]
106+
107+
//! [apply]
108+
void Apply(bigtable::Table& table) {
109+
// Write several rows with some trivial data.
110+
for (int i = 0; i != 20; ++i) {
111+
// Note: This example uses sequential numeric IDs for simplicity, but
112+
// this can result in poor performance in a production application.
113+
// Since rows are stored in sorted order by key, sequential keys can
114+
// result in poor distribution of operations across nodes.
115+
//
116+
// For more information about how to design a Bigtable schema for the
117+
// best performance, see the documentation:
118+
//
119+
// https://cloud.google.com/bigtable/docs/schema-design
120+
char buf[32];
121+
snprintf(buf, sizeof(buf), "key-%06d", i);
122+
bigtable::SingleRowMutation mutation(buf);
123+
mutation.emplace_back(
124+
bigtable::SetCell("fam", "col0", "value0-" + std::to_string(i)));
125+
mutation.emplace_back(
126+
bigtable::SetCell("fam", "col1", "value2-" + std::to_string(i)));
127+
mutation.emplace_back(
128+
bigtable::SetCell("fam", "col2", "value3-" + std::to_string(i)));
129+
mutation.emplace_back(
130+
bigtable::SetCell("fam", "col3", "value4-" + std::to_string(i)));
131+
table.Apply(std::move(mutation));
132+
}
133+
}
134+
//! [apply]
135+
136+
//! [bulk apply]
137+
void BulkApply(bigtable::Table& table) {
138+
// Write several rows in a single operation, each row has some trivial data.
139+
bigtable::BulkMutation bulk;
140+
for (int i = 0; i != 5000; ++i) {
141+
// Note: This example uses sequential numeric IDs for simplicity, but
142+
// this can result in poor performance in a production application.
143+
// Since rows are stored in sorted order by key, sequential keys can
144+
// result in poor distribution of operations across nodes.
145+
//
146+
// For more information about how to design a Bigtable schema for the
147+
// best performance, see the documentation:
148+
//
149+
// https://cloud.google.com/bigtable/docs/schema-design
150+
char buf[32];
151+
snprintf(buf, sizeof(buf), "key-%06d", i);
152+
bigtable::SingleRowMutation mutation(buf);
153+
mutation.emplace_back(
154+
bigtable::SetCell("fam", "col0", "value0-" + std::to_string(i)));
155+
mutation.emplace_back(
156+
bigtable::SetCell("fam", "col1", "value2-" + std::to_string(i)));
157+
mutation.emplace_back(
158+
bigtable::SetCell("fam", "col2", "value3-" + std::to_string(i)));
159+
mutation.emplace_back(
160+
bigtable::SetCell("fam", "col3", "value4-" + std::to_string(i)));
161+
bulk.emplace_back(std::move(mutation));
162+
}
163+
table.BulkApply(std::move(bulk));
164+
}
165+
//! [bulk apply]
166+
167+
//! [read row]
168+
void ReadRow(bigtable::Table& table) {
169+
// Filter the results, only include the latest value on each cell.
170+
auto filter = bigtable::Filter::Latest(1);
171+
// Read a row, this returns a tuple (bool, row)
172+
std::pair<bool, bigtable::Row> tuple =
173+
table.ReadRow(MAGIC_ROW_KEY, std::move(filter));
174+
if (not tuple.first) {
175+
std::cout << "Row " << MAGIC_ROW_KEY << " not found" << std::endl;
176+
return;
177+
}
178+
std::cout << "key: " << tuple.second.row_key() << "\n";
179+
for (auto& cell : tuple.second.cells()) {
180+
std::cout << " " << cell.family_name() << ":" << cell.column_qualifier()
181+
<< " = <" << cell.value() << ">\n";
182+
}
183+
std::cout << std::flush;
184+
}
185+
//! [read row]
186+
187+
//! [read rows]
188+
void ReadRows(bigtable::Table& table) {
189+
// Create the range of rows to read.
190+
auto range = bigtable::RowRange::Range("key-000010", "key-000020");
191+
// Filter the results, only include values from the "col0" column in the
192+
// "fam" column family, and only get the latest value.
193+
auto filter = bigtable::Filter::Chain(
194+
bigtable::Filter::ColumnRangeClosed("fam", "col0", "col0"),
195+
bigtable::Filter::Latest(1));
196+
// Read and print the rows.
197+
for (auto const& row : table.ReadRows(range, filter)) {
198+
if (row.cells().size() != 1) {
199+
std::ostringstream os;
200+
os << "Unexpected number of cells in " << row.row_key();
201+
throw std::runtime_error(os.str());
202+
}
203+
auto const& cell = row.cells().at(0);
204+
std::cout << cell.row_key() << " = [" << cell.value() << "]\n";
205+
}
206+
std::cout << std::flush;
207+
}
208+
//! [read rows]
209+
210+
//! [check and mutate]
211+
void CheckAndMutate(bigtable::Table& table) {
212+
// Check if the latest value of the flip-flop column is "on".
213+
auto predicate = bigtable::Filter::Chain(
214+
bigtable::Filter::ColumnRangeClosed("fam", "flip-flop", "flip-flop"),
215+
bigtable::Filter::Latest(1), bigtable::Filter::ValueRegex("on"));
216+
// If the predicate matches, change the latest value to "off", otherwise,
217+
// change the latest value to "on". Modify the "flop-flip" column at the
218+
// same time.
219+
table.CheckAndMutateRow(MAGIC_ROW_KEY, std::move(predicate),
220+
{bigtable::SetCell("fam", "flip-flop", "off"),
221+
bigtable::SetCell("fam", "flop-flip", "on")},
222+
{bigtable::SetCell("fam", "flip-flop", "on"),
223+
bigtable::SetCell("fam", "flop-flip", "off")});
224+
}
225+
//! [check and mutate]
226+
227+
//! [read modify write]
228+
void ReadModifyWrite(bigtable::Table& table) {
229+
auto row = table.ReadModifyWriteRow(
230+
MAGIC_ROW_KEY,
231+
bigtable::ReadModifyWriteRule::IncrementAmount("fam", "counter", 1),
232+
bigtable::ReadModifyWriteRule::AppendValue("fam", "list", ";element"));
233+
std::cout << row.row_key() << "\n";
234+
for (auto const& cell : row.cells()) {
235+
}
236+
}
237+
//! [read modify write]
238+
239+
//! [sample row keys]
240+
void SampleRows(bigtable::Table& table) {
241+
auto samples = table.SampleRows<std::vector>();
242+
for (auto const& sample : samples) {
243+
std::cout << "key=" << sample.row_key << " - " << sample.offset_bytes
244+
<< "\n";
245+
}
246+
std::cout << std::flush;
247+
}
248+
//! [sample row keys]
249+
250+
} // anonymous namespace
251+
252+
int main(int argc, char* argv[]) try {
253+
auto print_usage = [argv]() {
254+
std::string const cmd = argv[0];
255+
auto last_slash = std::string(cmd).find_last_of('/');
256+
auto program = cmd.substr(last_slash + 1);
257+
std::cerr << "Usage: " << program
258+
<< " <command> <project_id> <instance_id> <table_id>"
259+
<< "\n\n"
260+
<< "Examples:\n"
261+
<< " " << program
262+
<< " create-table my-project my-instance example-table\n"
263+
<< " " << program
264+
<< " write my-project my-instance example-table" << std::endl;
265+
};
266+
267+
if (argc != 5) {
268+
print_usage();
269+
return 1;
270+
}
271+
272+
std::string const command = argv[1];
273+
std::string const project_id = argv[2];
274+
std::string const instance_id = argv[3];
275+
std::string const table_id = argv[4];
276+
277+
// Connect to the Cloud Bigtable admin endpoint.
278+
//! [connect admin]
279+
bigtable::TableAdmin admin(
280+
bigtable::CreateDefaultAdminClient(project_id, bigtable::ClientOptions()),
281+
instance_id);
282+
//! [connect admin]
283+
284+
// Connect to the Cloud Bigtable endpoint.
285+
//! [connect data]
286+
bigtable::Table table(bigtable::CreateDefaultDataClient(
287+
project_id, instance_id, bigtable::ClientOptions()),
288+
table_id);
289+
//! [connect data]
290+
291+
if (command == "create-table") {
292+
CreateTable(admin, table_id);
293+
} else if (command == "list-tables") {
294+
ListTables(admin);
295+
} else if (command == "get-table") {
296+
GetTable(admin, table_id);
297+
} else if (command == "delete-table") {
298+
DeleteTable(admin, table_id);
299+
} else if (command == "modify-table") {
300+
ModifyTable(admin, table_id);
301+
} else if (command == "drop-all-rows") {
302+
DropAllRows(admin, table_id);
303+
} else if (command == "drop-rows-by-prefix") {
304+
DropRowsByPrefix(admin, table_id);
305+
} else if (command == "apply") {
306+
Apply(table);
307+
} else if (command == "bulk-apply") {
308+
BulkApply(table);
309+
} else if (command == "read-row" or command == "read") {
310+
ReadRow(table);
311+
} else if (command == "read-rows" or command == "scan") {
312+
ReadRows(table);
313+
} else if (command == "check-and-mutate") {
314+
CheckAndMutate(table);
315+
} else if (command == "read-modify-write") {
316+
ReadModifyWrite(table);
317+
} else if (command == "sample-rows") {
318+
SampleRows(table);
319+
} else {
320+
std::cerr << "Unknown command: " << command << std::endl;
321+
print_usage();
322+
}
323+
324+
return 0;
325+
} catch (std::exception const& ex) {
326+
std::cerr << "Standard C++ exception raised: " << ex.what() << std::endl;
327+
return 1;
328+
}

0 commit comments

Comments
 (0)