Skip to content

Commit 9304a3e

Browse files
authored
feat(storage): Add samples for AppendableObject and OpenObject (#15365)
* feat(storage): Add samples for AppendableObject and OpenObject * correct the typo * format the file
1 parent 6274cc6 commit 9304a3e

File tree

1 file changed

+191
-9
lines changed

1 file changed

+191
-9
lines changed

google/cloud/storage/examples/storage_async_samples.cc

Lines changed: 191 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,53 @@ void InsertObjectVectorVectors(
156156
}
157157

158158
#if GOOGLE_CLOUD_CPP_HAVE_COROUTINES
159-
void OpenObject(google::cloud::storage_experimental::AsyncClient& client,
160-
std::vector<std::string> const& argv) {
161-
//! [open-object]
159+
void OpenObjectSingleRangedRead(
160+
google::cloud::storage_experimental::AsyncClient& client,
161+
std::vector<std::string> const& argv) {
162+
//! [open-object-single-ranged-read]
163+
namespace gcs_ex = google::cloud::storage_experimental;
164+
165+
// Helper coroutine to count newlines returned by an AsyncReader.
166+
// This helps consume the data from the read operation.
167+
auto count_newlines =
168+
[](gcs_ex::AsyncReader reader,
169+
gcs_ex::AsyncToken token) -> google::cloud::future<std::uint64_t> {
170+
std::uint64_t count = 0;
171+
while (token.valid()) {
172+
auto [payload, t] = (co_await reader.Read(std::move(token))).value();
173+
token = std::move(t);
174+
for (auto const& buffer : payload.contents()) {
175+
count += std::count(buffer.begin(), buffer.end(), '\n');
176+
}
177+
}
178+
co_return count;
179+
};
180+
181+
auto coro =
182+
[&count_newlines](
183+
gcs_ex::AsyncClient& client, std::string bucket_name,
184+
std::string object_name) -> google::cloud::future<std::uint64_t> {
185+
auto descriptor =
186+
(co_await client.Open(gcs_ex::BucketName(std::move(bucket_name)),
187+
std::move(object_name)))
188+
.value();
189+
190+
auto [reader, token] = descriptor.Read(0, 1024);
191+
192+
co_return co_await count_newlines(std::move(reader), std::move(token));
193+
};
194+
//! [open-object-single-ranged-read]
195+
196+
// The example is easier to test if we call the coroutine and block
197+
// until it completes.
198+
auto const count = coro(client, argv.at(0), argv.at(1)).get();
199+
std::cout << "The range contains " << count << " newlines\n";
200+
}
201+
202+
void OpenObjectMultipleRangedRead(
203+
google::cloud::storage_experimental::AsyncClient& client,
204+
std::vector<std::string> const& argv) {
205+
//! [open-object-multiple-ranged-read]
162206
namespace gcs_ex = google::cloud::storage_experimental;
163207
// Helper coroutine, count lines returned by a AsyncReader
164208
auto count_newlines =
@@ -191,13 +235,56 @@ void OpenObject(google::cloud::storage_experimental::AsyncClient& client,
191235
auto c2 = count_newlines(std::move(r2), std::move(t2));
192236
co_return (co_await std::move(c1)) + (co_await std::move(c2));
193237
};
194-
//! [open-object]
238+
//! [open-object-multiple-ranged-read]
195239
// The example is easier to test and run if we call the coroutine and block
196240
// until it completes.
197241
auto const count = coro(client, argv.at(0), argv.at(1)).get();
198242
std::cout << "The ranges contain " << count << " newlines\n";
199243
}
200244

245+
void OpenObjectReadFullObject(
246+
google::cloud::storage_experimental::AsyncClient& client,
247+
std::vector<std::string> const& argv) {
248+
//! [open-object-read-full-object]
249+
namespace gcs_ex = google::cloud::storage_experimental;
250+
251+
// Helper coroutine to count newlines returned by an AsyncReader.
252+
// This helps consume the data from the read operation.
253+
auto count_newlines =
254+
[](gcs_ex::AsyncReader reader,
255+
gcs_ex::AsyncToken token) -> google::cloud::future<std::uint64_t> {
256+
std::uint64_t count = 0;
257+
while (token.valid()) {
258+
auto [payload, t] = (co_await reader.Read(std::move(token))).value();
259+
token = std::move(t);
260+
for (auto const& buffer : payload.contents()) {
261+
count += std::count(buffer.begin(), buffer.end(), '\n');
262+
}
263+
}
264+
co_return count;
265+
};
266+
267+
auto coro =
268+
[&count_newlines](
269+
gcs_ex::AsyncClient& client, std::string bucket_name,
270+
std::string object_name) -> google::cloud::future<std::uint64_t> {
271+
auto descriptor =
272+
(co_await client.Open(gcs_ex::BucketName(std::move(bucket_name)),
273+
std::move(object_name)))
274+
.value();
275+
276+
auto [reader, token] = descriptor.ReadFromOffset(0);
277+
278+
co_return co_await count_newlines(std::move(reader), std::move(token));
279+
};
280+
//! [open-object-read-full-object]
281+
282+
// The example is easier to test if we call the coroutine and block
283+
// until it completes.
284+
auto const count = coro(client, argv.at(0), argv.at(1)).get();
285+
std::cout << "The range contains " << count << " newlines\n";
286+
}
287+
201288
void ReadObject(google::cloud::storage_experimental::AsyncClient& client,
202289
std::vector<std::string> const& argv) {
203290
//! [read-object]
@@ -564,6 +651,69 @@ void StartAppendableObjectUpload(
564651
std::cout << "File successfully uploaded " << object.DebugString() << "\n";
565652
}
566653

654+
void ResumeAppendableObjectUpload(
655+
google::cloud::storage_experimental::AsyncClient& client,
656+
std::vector<std::string> const& argv) {
657+
//! [resume-appendable-object-upload]
658+
namespace gcs = google::cloud::storage;
659+
namespace gcs_ex = google::cloud::storage_experimental;
660+
auto coro = [](gcs_ex::AsyncClient& client, std::string bucket_name,
661+
std::string object_name)
662+
-> google::cloud::future<google::storage::v2::Object> {
663+
// Start an appendable upload and write some data.
664+
auto [writer, token] = (co_await client.StartAppendableObjectUpload(
665+
gcs_ex::BucketName(bucket_name), object_name))
666+
.value();
667+
for (int i = 0; i != 5; ++i) {
668+
auto line = gcs_ex::WritePayload(std::vector<std::string>{
669+
std::string("line number "), std::to_string(i), std::string("\n")});
670+
token =
671+
(co_await writer.Write(std::move(token), std::move(line))).value();
672+
}
673+
// The writer is closed, but the upload is not finalized. The object remains
674+
// appendable.
675+
auto close_status = co_await writer.Close();
676+
if (!close_status.ok()) {
677+
throw std::runtime_error(close_status.message());
678+
}
679+
680+
// To resume the upload we need the object's generation. We can use the
681+
// regular GCS client to get the latest metadata.
682+
auto regular_client = gcs::Client();
683+
auto metadata =
684+
regular_client.GetObjectMetadata(bucket_name, object_name).value();
685+
686+
// Now resume the upload from the beginning.
687+
std::tie(writer, token) = (co_await client.ResumeAppendableObjectUpload(
688+
gcs_ex::BucketName(bucket_name), object_name,
689+
metadata.generation()))
690+
.value();
691+
692+
// The writer returns the persisted size, which can be used to understand
693+
// where to resume from.
694+
auto persisted_size = absl::get<std::int64_t>(writer.PersistedState());
695+
std::cout << "Upload resumed at offset " << persisted_size << "\n";
696+
697+
// Append the rest of the data.
698+
for (int i = 5; i != 10; ++i) {
699+
auto line = gcs_ex::WritePayload(std::vector<std::string>{
700+
std::string("line number "), std::to_string(i), std::string("\n")});
701+
token =
702+
(co_await writer.Write(std::move(token), std::move(line))).value();
703+
}
704+
705+
// Finalize the upload and return the object metadata.
706+
co_return (co_await writer.Finalize(std::move(token))).value();
707+
};
708+
//! [resume-appendable-object-upload]
709+
710+
// The example is easier to test and run if we call the coroutine and block
711+
// until it completes.
712+
auto const object = coro(client, argv.at(0), argv.at(1)).get();
713+
std::cout << "File successfully uploaded and finalized "
714+
<< object.DebugString() << "\n";
715+
}
716+
567717
void RewriteObject(google::cloud::storage_experimental::AsyncClient& client,
568718
std::vector<std::string> const& argv) {
569719
//! [rewrite-object]
@@ -653,8 +803,20 @@ void ResumeRewrite(google::cloud::storage_experimental::AsyncClient& client,
653803
}
654804

655805
#else
656-
void OpenObject(google::cloud::storage_experimental::AsyncClient&,
657-
std::vector<std::string> const&) {
806+
void OpenObjectSingleRangedRead(
807+
google::cloud::storage_experimental::AsyncClient&,
808+
std::vector<std::string> const&) {
809+
std::cerr << "AsyncClient::Open() example requires coroutines\n";
810+
}
811+
812+
void OpenObjectMultipleRangedRead(
813+
google::cloud::storage_experimental::AsyncClient&,
814+
std::vector<std::string> const&) {
815+
std::cerr << "AsyncClient::Open() example requires coroutines\n";
816+
}
817+
818+
void OpenObjectReadFullObject(google::cloud::storage_experimental::AsyncClient&,
819+
std::vector<std::string> const&) {
658820
std::cerr << "AsyncClient::Open() example requires coroutines\n";
659821
}
660822

@@ -726,6 +888,13 @@ void StartAppendableObjectUpload(
726888
"coroutines\n";
727889
}
728890

891+
void ResumeAppendableObjectUpload(
892+
google::cloud::storage_experimental::AsyncClient&,
893+
std::vector<std::string> const&) {
894+
std::cerr << "AsyncClient::ResumeAppendableObjectUpload() example requires "
895+
"coroutines\n";
896+
}
897+
729898
void RewriteObject(google::cloud::storage_experimental::AsyncClient&,
730899
std::vector<std::string> const&) {
731900
std::cerr << "AsyncClient::RewriteObject() example requires coroutines\n";
@@ -901,8 +1070,15 @@ void AutoRun(std::vector<std::string> const& argv) {
9011070
scheduled_for_delete.push_back(std::move(object_name));
9021071
object_name = examples::MakeRandomObjectName(generator, "object-");
9031072

904-
std::cout << "Running the OpenObject() example" << std::endl;
905-
OpenObject(client, {bucket_name, composed_name});
1073+
std::cout << "Running the OpenObjectSingleRangedRead() example" << std::endl;
1074+
OpenObjectSingleRangedRead(client, {bucket_name, composed_name});
1075+
1076+
std::cout << "Running the OpenObjectMultipleRangedRead() example"
1077+
<< std::endl;
1078+
OpenObjectMultipleRangedRead(client, {bucket_name, composed_name});
1079+
1080+
std::cout << "Running the OpenObjectReadFullObject() example" << std::endl;
1081+
OpenObjectReadFullObject(client, {bucket_name, composed_name});
9061082

9071083
std::cout << "Running the ReadObject() example" << std::endl;
9081084
ReadObject(client, {bucket_name, composed_name});
@@ -1064,7 +1240,11 @@ int main(int argc, char* argv[]) try {
10641240
make_entry("insert-object-vector", {}, InsertObjectVector),
10651241
make_entry("insert-object-vector-strings", {}, InsertObjectVectorStrings),
10661242
make_entry("insert-object-vector-vectors", {}, InsertObjectVectorVectors),
1067-
make_entry("open-object", {}, OpenObject),
1243+
make_entry("open-object-single-ranged-read", {},
1244+
OpenObjectSingleRangedRead),
1245+
make_entry("open-object-multiple-ranged-read", {},
1246+
OpenObjectMultipleRangedRead),
1247+
make_entry("open-object-read-full-object", {}, OpenObjectReadFullObject),
10681248
make_entry("read-object", {}, ReadObject),
10691249
make_entry("read-all", {}, ReadAll),
10701250
make_entry("read-object-range", {}, ReadObjectRange),
@@ -1086,6 +1266,8 @@ int main(int argc, char* argv[]) try {
10861266

10871267
make_entry("start-appendable-object-upload", {},
10881268
StartAppendableObjectUpload),
1269+
make_entry("resume-appendable-object-upload", {},
1270+
ResumeAppendableObjectUpload),
10891271

10901272
make_entry("rewrite-object", {"<destination>"}, RewriteObject),
10911273
make_entry("resume-rewrite-object", {"<destination>"}, ResumeRewrite),

0 commit comments

Comments
 (0)