summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChenhao Qu <chenhao.qu@mongodb.com>2022-04-13 01:46:12 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-04-13 02:12:41 +0000
commitb3cded481b3b70c766338a729014e64bf71a97e6 (patch)
tree5bcd0f836bfc241d3061ad26e1c46707b47d1c62 /src
parent583df21242096af2467a4b94ff9cb2a86d55bbaf (diff)
downloadmongo-b3cded481b3b70c766338a729014e64bf71a97e6.tar.gz
Import wiredtiger: 7a7d6bf9ab40cd5635ee960fac1b21edf118a007 from branch mongodb-master
ref: 07cee370d8..7a7d6bf9ab for: 6.0.0-rc0 WT-8998 S3 extension - Uniform coding standards, error handling and logging
Diffstat (limited to 'src')
-rw-r--r--src/third_party/wiredtiger/dist/s_string.ok4
-rw-r--r--src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_connection.cpp134
-rw-r--r--src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_connection.h45
-rw-r--r--src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_log_system.cpp61
-rw-r--r--src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_log_system.h62
-rw-r--r--src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_storage_source.cpp695
-rw-r--r--src/third_party/wiredtiger/ext/storage_sources/s3_store/test/test_s3_connection.cpp144
-rw-r--r--src/third_party/wiredtiger/import.data2
8 files changed, 595 insertions, 552 deletions
diff --git a/src/third_party/wiredtiger/dist/s_string.ok b/src/third_party/wiredtiger/dist/s_string.ok
index 8e94b159ae8..da396a97162 100644
--- a/src/third_party/wiredtiger/dist/s_string.ok
+++ b/src/third_party/wiredtiger/dist/s_string.ok
@@ -17,6 +17,7 @@ ASAN
ASM
AUS
AWS
+AWS's
Addr
Ailamaki
Alakuijala
@@ -99,6 +100,7 @@ Coverity
CreateFileMapping
CreateFileMappingW
CreateFileW
+Crt
Crummey
CustomersPhone
DAX
@@ -268,6 +270,7 @@ LibFuzzer
LmRrSVv
LoadLoad
LockFile
+LogSystemInterface
Lookaside
Lookup
MADV
@@ -392,6 +395,7 @@ RocksDB
Rogerio
Runtime
SDK
+SDK's
SDKOptions
SIMD
SLIST
diff --git a/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_connection.cpp b/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_connection.cpp
index a9983ea5f94..1ee103a0690 100644
--- a/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_connection.cpp
+++ b/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_connection.cpp
@@ -1,4 +1,32 @@
-#include <aws/core/Aws.h>
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "s3_connection.h"
+
#include <aws/s3-crt/model/DeleteObjectRequest.h>
#include <aws/s3-crt/model/ListObjectsV2Request.h>
#include <aws/s3-crt/model/PutObjectRequest.h>
@@ -6,52 +34,41 @@
#include <aws/s3-crt/model/HeadObjectRequest.h>
#include <aws/s3-crt/model/HeadBucketRequest.h>
-#include "s3_connection.h"
-
#include <fstream>
#include <iostream>
-#include <string>
-#include <vector>
-#define S3_ALLOCATION_TAG ""
-/*
- * S3Connection --
- * Constructor for AWS S3 bucket connection with provided credentials.
- */
+// Constructor for AWS S3 bucket connection with provided credentials.
S3Connection::S3Connection(const Aws::Auth::AWSCredentials &credentials,
const Aws::S3Crt::ClientConfiguration &config, const std::string &bucketName,
const std::string &objPrefix)
: _s3CrtClient(credentials, config), _bucketName(bucketName), _objectPrefix(objPrefix)
{
- /* Confirm that we can access the bucket, else fail. */
+ // Confirm that we can access the bucket, else fail.
bool exists;
int ret = BucketExists(exists);
- if (ret != 0 || !exists)
+ if (!exists)
throw std::invalid_argument(_bucketName + " : No such bucket.");
+ if (ret != 0)
+ throw std::invalid_argument(_bucketName + " :Unable to access bucket.");
}
-/*
- * S3Connection --
- * Constructor for AWS S3 bucket connection with credentials in local file.
- * https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html
- */
+// Constructor for AWS S3 bucket connection with credentials in local file.
S3Connection::S3Connection(const Aws::S3Crt::ClientConfiguration &config,
const std::string &bucketName, const std::string &objPrefix)
: _s3CrtClient(config), _bucketName(bucketName), _objectPrefix(objPrefix)
{
- /* Confirm that we can access the bucket, else fail. */
+ // Confirm that we can access the bucket, else fail.
bool exists;
int ret = BucketExists(exists);
- if (ret != 0 || !exists)
+ if (!exists)
throw std::invalid_argument(_bucketName + " : No such bucket.");
+ if (ret != 0)
+ throw std::invalid_argument(_bucketName + " : Unable to access bucket.");
}
-/*
- * ListObjects --
- * Builds a list of object names, with prefix matching, from an S3 bucket into a vector. The
- * batchSize parameter specifies the maximum number of objects returned in each AWS response, up
- * to 1000. Returns 0 if success, otherwise 1.
- */
+// Builds a list of object names, with prefix matching, from an S3 bucket into a vector. The
+// batchSize parameter specifies the maximum number of objects returned in each AWS response, up
+// to 1000. Returns 0 if success, otherwise 1.
int
S3Connection::ListObjects(const std::string &prefix, std::vector<std::string> &objects,
uint32_t batchSize, bool listSingle) const
@@ -66,14 +83,14 @@ S3Connection::ListObjects(const std::string &prefix, std::vector<std::string> &o
return (1);
auto result = outcomes.GetResult();
- /* Returning the object name with the prefix stripped. */
+ // Returning the object name with the prefix stripped.
for (const auto &object : result.GetContents())
objects.push_back(object.GetKey().substr(_objectPrefix.length()));
if (listSingle)
return (0);
- /* Continuation token will be an empty string if we have returned all possible objects. */
+ // Continuation token will be an empty string if we have returned all possible objects.
std::string continuationToken = result.GetNextContinuationToken();
while (continuationToken != "") {
request.SetContinuationToken(continuationToken);
@@ -88,15 +105,12 @@ S3Connection::ListObjects(const std::string &prefix, std::vector<std::string> &o
return (0);
}
-/*
- * PutObject --
- * Puts an object into an S3 bucket. Returns 0 if success, otherwise 1.
- */
+// Puts an object into an S3 bucket. Returns 0 if success, otherwise 1.
int
S3Connection::PutObject(const std::string &objectKey, const std::string &fileName) const
{
std::shared_ptr<Aws::IOStream> inputData = Aws::MakeShared<Aws::FStream>(
- "s3-source", fileName.c_str(), std::ios_base::in | std::ios_base::binary);
+ s3AllocationTag, fileName.c_str(), std::ios_base::in | std::ios_base::binary);
Aws::S3Crt::Model::PutObjectRequest request;
request.SetBucket(_bucketName);
@@ -111,10 +125,7 @@ S3Connection::PutObject(const std::string &objectKey, const std::string &fileNam
return (1);
}
-/*
- * DeleteObject --
- * Deletes an object from S3 bucket. Returns 0 if success, otherwise 1.
- */
+// Deletes an object from S3 bucket. Returns 0 if success, otherwise 1.
int
S3Connection::DeleteObject(const std::string &objectKey) const
{
@@ -129,24 +140,19 @@ S3Connection::DeleteObject(const std::string &objectKey) const
return (1);
}
-/*
- * GetObject --
- * Retrieves an object from S3. The object is downloaded to disk at the specified location.
- */
+// Retrieves an object from S3. The object is downloaded to disk at the specified location.
int
S3Connection::GetObject(const std::string &objectKey, const std::string &path) const
{
Aws::S3Crt::Model::GetObjectRequest request;
request.SetBucket(_bucketName);
request.SetKey(_objectPrefix + objectKey);
- /*
- * The S3 Object should be downloaded to disk rather than into an in-memory buffer. Use a custom
- * response stream factory to specify how the response should be downloaded.
- * https://sdk.amazonaws.com/cpp/api/0.14.3/class_aws_1_1_utils_1_1_stream_1_1_response_stream.html
- */
+
+ // The S3 Object should be downloaded to disk rather than into an in-memory buffer. Use a custom
+ // response stream factory to specify how the response should be downloaded.
request.SetResponseStreamFactory([=]() {
return (Aws::New<Aws::FStream>(
- S3_ALLOCATION_TAG, path, std::ios_base::out | std::ios_base::binary));
+ s3AllocationTag, path, std::ios_base::out | std::ios_base::binary));
});
if (!_s3CrtClient.GetObject(request).IsSuccess())
@@ -155,11 +161,8 @@ S3Connection::GetObject(const std::string &objectKey, const std::string &path) c
return (0);
}
-/*
- * ObjectExists --
- * Checks whether an object with the given key exists in the S3 bucket and also retrieves
- * size of the object.
- */
+// Checks whether an object with the given key exists in the S3 bucket and also retrieves
+// size of the object.
int
S3Connection::ObjectExists(const std::string &objectKey, bool &exists, size_t &objectSize) const
{
@@ -171,10 +174,8 @@ S3Connection::ObjectExists(const std::string &objectKey, bool &exists, size_t &o
request.SetKey(_objectPrefix + objectKey);
Aws::S3Crt::Model::HeadObjectOutcome outcome = _s3CrtClient.HeadObject(request);
- /*
- * If an object with the given key does not exist the HEAD request will return a 404.
- * https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html Do not fail in this case.
- */
+ // If an object with the given key does not exist the HEAD request will return a 404.
+ // Do not fail in this case.
if (outcome.IsSuccess()) {
exists = true;
objectSize = outcome.GetResult().GetContentLength();
@@ -182,17 +183,12 @@ S3Connection::ObjectExists(const std::string &objectKey, bool &exists, size_t &o
} else if (outcome.GetError().GetResponseCode() == Aws::Http::HttpResponseCode::NOT_FOUND)
return (0);
- /*
- * Fix later, return a proper error code. Not sure if we always have
- * outcome.GetError().GetResponseCode()
- */
+ // Fix later, return a proper error code. Not sure if we always have
+ // outcome.GetError().GetResponseCode()
return (1);
}
-/*
- * BucketExists --
- * Checks whether the bucket configured for the class is accessible to us or not.
- */
+// Checks whether the bucket configured for the class is accessible to us or not.
int
S3Connection::BucketExists(bool &exists) const
{
@@ -202,19 +198,15 @@ S3Connection::BucketExists(bool &exists) const
request.WithBucket(_bucketName);
Aws::S3Crt::Model::HeadBucketOutcome outcome = _s3CrtClient.HeadBucket(request);
- /*
- * If an object with the given key does not exist the HEAD request will return a 404.
- * https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadBucket.html Do not fail in this case.
- */
+ // If an object with the given key does not exist the HEAD request will return a 404.
+ // Do not fail in this case.
if (outcome.IsSuccess()) {
exists = true;
return (0);
} else if (outcome.GetError().GetResponseCode() == Aws::Http::HttpResponseCode::NOT_FOUND)
return (0);
- /*
- * Fix later, return a proper error code. Not sure if we always have
- * outcome.GetError().GetResponseCode()
- */
+ // Fix later, return a proper error code. Not sure if we always have
+ // outcome.GetError().GetResponseCode()
return (1);
}
diff --git a/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_connection.h b/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_connection.h
index 51085988225..314173f9928 100644
--- a/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_connection.h
+++ b/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_connection.h
@@ -1,4 +1,31 @@
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
#ifndef S3CONNECTION
#define S3CONNECTION
@@ -10,12 +37,18 @@
#include <string>
#include <vector>
-/*
- * Class to represent an active connection to the AWS S3 endpoint. Allows for interaction with S3
- * client.
- */
+// This class represents an active connection to the AWS S3 endpoint and allows for interaction with
+// S3-Crt client. The S3Connection exposes an API to list the bucket contents filtered by a
+// directory and a prefix, check for an object's existence in the bucket, put an object to the
+// cloud, and get the object from the cloud. Though not required for the file system's
+// implementation, the class also provides the means to delete the objects to clean up artifacts
+// from the internal unit testing. Note we are using S3-Crt client in this class, which differs to
+// the S3 client.
class S3Connection {
public:
+ // We have two constructors for the two different ways to start a S3 connection.
+ // First constructor uses provided credentials, the following uses credentials stored in a local
+ // file.
S3Connection(const Aws::Auth::AWSCredentials &credentials,
const Aws::S3Crt::ClientConfiguration &config, const std::string &bucketName,
const std::string &objPrefix = "");
@@ -35,6 +68,10 @@ class S3Connection {
const std::string _bucketName;
const std::string _objectPrefix;
+ // Tag that can be set and used when uploading or retrieving objects from the S3.
+ // Tagging in S3 allows for categorization of objects, as well as other benefits.
+ static inline const char *const s3AllocationTag = "s3-source";
+
int BucketExists(bool &exists) const;
};
#endif
diff --git a/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_log_system.cpp b/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_log_system.cpp
index 2dceece391b..0445b8f3880 100644
--- a/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_log_system.cpp
+++ b/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_log_system.cpp
@@ -1,12 +1,42 @@
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
#include <aws/core/Aws.h>
#include "s3_log_system.h"
#include <cstdarg>
+// Constructor for S3LogSystem that calls to set the WiredTiger verbosity level.
S3LogSystem::S3LogSystem(WT_EXTENSION_API *wtApi, uint32_t wtVerbosityLevel) : _wtApi(wtApi)
{
SetWtVerbosityLevel(wtVerbosityLevel);
}
+// Overrides the interface's Log method to write the AWS SDK log stream to WiredTiger's log stream
+// using variadic style through a helper function. Inherited from AWS's LogSystemInterface.
void
S3LogSystem::Log(Aws::Utils::Logging::LogLevel logLevel, const char *tag, const char *format, ...)
{
@@ -33,6 +63,8 @@ S3LogSystem::Log(Aws::Utils::Logging::LogLevel logLevel, const char *tag, const
va_end(args);
}
+// Overrides the interface's LogStream method to write the AWS SDK log stream to WiredTiger's log
+// stream through a helper function. Inherited from AWS's LogSystemInterface.
void
S3LogSystem::LogStream(
Aws::Utils::Logging::LogLevel logLevel, const char *tag, const Aws::OStringStream &messageStream)
@@ -40,50 +72,35 @@ S3LogSystem::LogStream(
LogAwsMessage(tag, messageStream.rdbuf()->str().c_str());
}
+// Directs the message to WiredTiger's log streams.
void
S3LogSystem::LogAwsMessage(const char *tag, const std::string &message) const
{
_wtApi->err_printf(_wtApi, NULL, "%s : %s", tag, message.c_str());
}
+// Directs the message to WiredTiger's log streams matched at WiredTiger's log stream levels.
void
S3LogSystem::LogVerboseMessage(int32_t verbosityLevel, const std::string &message) const
{
if (verbosityLevel <= _wtVerbosityLevel) {
- /* Use err_printf for error and warning messages and use msg_printf for notice, info and
- * debug messages. */
- if (verbosityLevel < -1)
+ // Use err_printf for error and warning messages and use msg_printf for notice, info and
+ // debug messages.
+ if (verbosityLevel < WT_VERBOSE_NOTICE)
_wtApi->err_printf(_wtApi, NULL, "%s", message.c_str());
else
_wtApi->msg_printf(_wtApi, NULL, "%s", message.c_str());
}
}
-void
-S3LogSystem::LogErrorMessage(const std::string &message) const
-{
- LogVerboseMessage(WT_VERBOSE_ERROR, message);
-}
-
-void
-S3LogSystem::LogDebugMessage(const std::string &message) const
-{
- LogVerboseMessage(WT_VERBOSE_DEBUG, message);
-}
-
+// Sets the WiredTiger verbosity level by mapping the AWS SDK log level.
void
S3LogSystem::SetWtVerbosityLevel(int32_t wtVerbosityLevel)
{
_wtVerbosityLevel = wtVerbosityLevel;
- /* If the verbosity level is out of range it will default to AWS SDK Error level. */
+ // If the verbosity level is out of range it will default to AWS SDK Error level.
if (verbosityMapping.find(_wtVerbosityLevel) != verbosityMapping.end())
_awsLogLevel = verbosityMapping.at(_wtVerbosityLevel);
else
_awsLogLevel = Aws::Utils::Logging::LogLevel::Error;
}
-
-void
-S3LogSystem::Flush()
-{
- return;
-}
diff --git a/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_log_system.h b/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_log_system.h
index 06202dbe84f..e6e8ddf2d5b 100644
--- a/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_log_system.h
+++ b/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_log_system.h
@@ -1,3 +1,33 @@
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef S3LOGSYSTEM
+#define S3LOGSYSTEM
+
#include <wiredtiger.h>
#include <wiredtiger_ext.h>
@@ -13,8 +43,11 @@ static const std::map<int32_t, Aws::Utils::Logging::LogLevel> verbosityMapping =
{-1, Aws::Utils::Logging::LogLevel::Info}, {0, Aws::Utils::Logging::LogLevel::Info},
{1, Aws::Utils::Logging::LogLevel::Debug}};
+// Provides the S3 Store with a logger implementation that redirects the generated logs to
+// WiredTiger's logging streams. This class implements AWS's LogSystemInterface class, an interface
+// for logging implementations. Functions are derived from the interface to incorporate the
+// logging with WiredTiger's logging system.
class S3LogSystem : public Aws::Utils::Logging::LogSystemInterface {
-
public:
S3LogSystem(WT_EXTENSION_API *wtApi, uint32_t wtVerbosityLevel);
Aws::Utils::Logging::LogLevel
@@ -26,10 +59,30 @@ class S3LogSystem : public Aws::Utils::Logging::LogSystemInterface {
Aws::Utils::Logging::LogLevel logLevel, const char *tag, const char *format, ...) override;
void LogStream(Aws::Utils::Logging::LogLevel logLevel, const char *tag,
const Aws::OStringStream &messageStream) override;
- void LogErrorMessage(const std::string &message) const;
- void LogDebugMessage(const std::string &message) const;
+
+ // Sends error messages to WiredTiger's error level log stream.
+ void
+ LogErrorMessage(const std::string &message) const
+ {
+ LogVerboseMessage(WT_VERBOSE_ERROR, message);
+ }
+
+ // Sends error messages to WiredTiger's debug level log stream.
+ void
+ LogDebugMessage(const std::string &message) const
+ {
+ LogVerboseMessage(WT_VERBOSE_DEBUG, message);
+ }
+
+ // Sets the WiredTiger Extension's verbosity level and matches the AWS log levels
+ // to this.
void SetWtVerbosityLevel(int32_t wtVerbosityLevel);
- void Flush() override;
+
+ // Inherited from AWS LogSystemInterface and is not used.
+ void
+ Flush()
+ {
+ }
private:
void LogAwsMessage(const char *tag, const std::string &message) const;
@@ -38,3 +91,4 @@ class S3LogSystem : public Aws::Utils::Logging::LogSystemInterface {
WT_EXTENSION_API *_wtApi;
int32_t _wtVerbosityLevel;
};
+#endif
diff --git a/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_storage_source.cpp b/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_storage_source.cpp
index 0ad2517ac62..d2547110fc4 100644
--- a/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_storage_source.cpp
+++ b/src/third_party/wiredtiger/ext/storage_sources/s3_store/s3_storage_source.cpp
@@ -25,104 +25,100 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
+
#include <wiredtiger.h>
#include <wiredtiger_ext.h>
-#include <sys/stat.h>
#include <fstream>
#include <list>
#include <errno.h>
-#include <unistd.h>
+#include <filesystem>
#include "s3_connection.h"
#include "s3_log_system.h"
#include <aws/auth/credentials.h>
#include <aws/core/Aws.h>
-#include <aws/core/auth/AWSCredentialsProvider.h>
-#include <aws/core/utils/memory/stl/AWSString.h>
#include <aws/core/utils/logging/AWSLogging.h>
#define UNUSED(x) (void)(x)
-#define FS2S3(fs) (((S3_FILE_SYSTEM *)(fs))->storage)
-
-struct S3_FILE_HANDLE;
-struct S3_FILE_SYSTEM;
-
-/* Statistics to be collected for the S3 storage. */
-struct S3_STATISTICS {
- /* Operations using AWS SDK. */
- uint64_t listObjectsCount; /* Number of S3 list objects requests */
- uint64_t putObjectCount; /* Number of S3 put object requests */
- uint64_t getObjectCount; /* Number of S3 get object requests */
- uint64_t objectExistsCount; /* Number of S3 object exists requests */
-
- /* Operations using WiredTiger's native file handle operations. */
- uint64_t fhOps; /* Number of non read/write file handle operations */
- uint64_t fhReadOps; /* Number of file handle read operations */
+#define FS2S3(fs) (((S3FileSystem *)(fs))->storage)
+
+struct S3FileHandle;
+struct S3FileSystem;
+
+// Statistics to be collected for the S3 storage.
+struct S3Statistics {
+ // Operations using AWS SDK.
+ uint64_t listObjectsCount; // Number of S3 list objects requests
+ uint64_t putObjectCount; // Number of S3 put object requests
+ uint64_t getObjectCount; // Number of S3 get object requests
+ uint64_t objectExistsCount; // Number of S3 object exists requests
+
+ // Operations using WiredTiger's native file handle operations.
+ uint64_t fhOps; // Number of non read/write file handle operations
+ uint64_t fhReadOps; // Number of file handle read operations
};
-/* S3 storage source structure. */
-struct S3_STORAGE {
- WT_STORAGE_SOURCE storageSource; /* Must come first */
- WT_EXTENSION_API *wtApi; /* Extension API */
+// S3 storage source structure.
+struct S3Storage {
+ WT_STORAGE_SOURCE storageSource; // Must come first
+ WT_EXTENSION_API *wtApi; // Extension API
std::shared_ptr<S3LogSystem> log;
- std::mutex fsListMutex; /* Protect the file system list */
- std::list<S3_FILE_SYSTEM *> fsList; /* List of initiated file systems */
- std::mutex fhMutex; /* Protect the file handle list*/
- std::list<S3_FILE_HANDLE *> fhList; /* List of open file handles */
+ std::mutex fsListMutex; // Protect the file system list
+ std::list<S3FileSystem *> fsList; // List of initiated file systems
+ std::mutex fhMutex; // Protect the file handle list
+ std::list<S3FileHandle *> fhList; // List of open file handles
- uint32_t referenceCount; /* Number of references to this storage source */
+ uint32_t referenceCount; // Number of references to this storage source
int32_t verbose;
- S3_STATISTICS statistics;
+ S3Statistics statistics;
};
-struct S3_FILE_SYSTEM {
- /* Must come first - this is the interface for the file system we are implementing. */
+struct S3FileSystem {
+ // Must come first - this is the interface for the file system we are implementing.
WT_FILE_SYSTEM fileSystem;
- S3_STORAGE *storage;
- /*
- * The S3_FILE_SYSTEM is built on top of the WT_FILE_SYSTEM. We require an instance of the
- * WT_FILE_SYSTEM in order to access the native WiredTiger filesystem functionality, such as the
- * native WT file handle open.
- */
+ S3Storage *storage;
+ // The S3_FILE_SYSTEM is built on top of the WT_FILE_SYSTEM. We require an instance of the
+ // WT_FILE_SYSTEM in order to access the native WiredTiger filesystem functionality, such as the
+ // native WT file handle open.
WT_FILE_SYSTEM *wtFileSystem;
S3Connection *connection;
- std::string cacheDir; /* Directory for cached objects */
- std::string homeDir; /* Owned by the connection */
+ std::string cacheDir; // Directory for cached objects
+ std::string homeDir; // Owned by the connection
};
-struct S3_FILE_HANDLE {
- WT_FILE_HANDLE iface; /* Must come first */
- S3_STORAGE *storage; /* Enclosing storage source */
- /*
- * Similarly, The S3_FILE_HANDLE is built on top of the WT_FILE_HANDLE. We require an instance
- * of the WT_FILE_HANDLE in order to access the native WiredTiger filehandle functionality, such
- * as the native WT file handle read and close.
- */
+struct S3FileHandle {
+ WT_FILE_HANDLE iface; // Must come first
+ S3Storage *storage; // Enclosing storage source
+
+ // Similarly, The S3FileHandle is built on top of the WT_FILE_HANDLE. We require an instance of
+ // the WT_FILE_HANDLE in order to access the native WiredTiger filehandle functionality, such as
+ // the native WT file handle read and close.
+
WT_FILE_HANDLE *wtFileHandle;
};
-/* Configuration variables for connecting to S3CrtClient. */
+// Configuration variables for connecting to S3CrtClient.
const double throughputTargetGbps = 5;
-const uint64_t partSize = 8 * 1024 * 1024; /* 8 MB. */
+const uint64_t partSize = 8 * 1024 * 1024; // 8 MB.
-/* Setting SDK options. */
+// Setting SDK options.
Aws::SDKOptions options;
static int S3GetDirectory(
- const S3_STORAGE &, const std::string &, const std::string &, bool, std::string &);
+ const S3Storage &, const std::string &, const std::string &, bool, std::string &);
static bool S3CacheExists(WT_FILE_SYSTEM *, const std::string &);
static std::string S3Path(const std::string &, const std::string &);
static std::string S3HomePath(WT_FILE_SYSTEM *, const char *);
static std::string S3CachePath(WT_FILE_SYSTEM *, const char *);
-static int S3Exist(WT_FILE_SYSTEM *, WT_SESSION *, const char *, bool *);
+static int S3FileExists(WT_FILE_SYSTEM *, WT_SESSION *, const char *, bool *);
static int S3CustomizeFileSystem(
WT_STORAGE_SOURCE *, WT_SESSION *, const char *, const char *, const char *, WT_FILE_SYSTEM **);
static int S3AddReference(WT_STORAGE_SOURCE *);
static int S3FileSystemTerminate(WT_FILE_SYSTEM *, WT_SESSION *);
-static int S3Open(
+static int S3FileOpen(
WT_FILE_SYSTEM *, WT_SESSION *, const char *, WT_FS_OPEN_FILE_TYPE, uint32_t, WT_FILE_HANDLE **);
static int S3Remove(WT_FILE_SYSTEM *, WT_SESSION *, const char *, uint32_t);
static int S3Rename(WT_FILE_SYSTEM *, WT_SESSION *, const char *, const char *, uint32_t);
@@ -131,25 +127,22 @@ static int S3FileRead(WT_FILE_HANDLE *, WT_SESSION *, wt_off_t, size_t, void *);
static int S3ObjectList(
WT_FILE_SYSTEM *, WT_SESSION *, const char *, const char *, char ***, uint32_t *);
static int S3ObjectListAdd(
- const S3_STORAGE &, char ***, const std::vector<std::string> &, const uint32_t);
+ const S3Storage &, char ***, const std::vector<std::string> &, const uint32_t);
static int S3ObjectListSingle(
WT_FILE_SYSTEM *, WT_SESSION *, const char *, const char *, char ***, uint32_t *);
static int S3ObjectListFree(WT_FILE_SYSTEM *, WT_SESSION *, char **, uint32_t);
-static void S3ShowStatistics(const S3_STORAGE &);
+static void S3LogStatistics(const S3Storage &);
static int S3FileClose(WT_FILE_HANDLE *, WT_SESSION *);
static int S3FileSize(WT_FILE_HANDLE *, WT_SESSION *, wt_off_t *);
static int S3FileLock(WT_FILE_HANDLE *, WT_SESSION *, bool);
-static int S3Size(WT_FILE_SYSTEM *, WT_SESSION *, const char *, wt_off_t *);
+static int S3ObjectSize(WT_FILE_SYSTEM *, WT_SESSION *, const char *, wt_off_t *);
-/*
- * S3Path --
- * Construct a pathname from the directory and the object name.
- */
+// Construct a pathname from the directory and the object name.
static std::string
S3Path(const std::string &dir, const std::string &name)
{
- /* Skip over "./" and variations (".//", ".///./././//") at the beginning of the name. */
+ // Skip over "./" and variations (".//", ".///./././//") at the beginning of the name.
int i = 0;
while (name[i] == '.') {
if (name[1] != '/')
@@ -162,46 +155,41 @@ S3Path(const std::string &dir, const std::string &name)
return (dir + "/" + strippedName);
}
-/*
- * S3Exist--
- * Return if the file exists. First checks the cache, and then the S3 Bucket.
- */
+// Return if the file exists. First checks the cache, and then the S3 Bucket.
static int
-S3Exist(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name, bool *exist)
+S3FileExists(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name, bool *fileExists)
{
- size_t objectSize;
- S3_FILE_SYSTEM *fs = (S3_FILE_SYSTEM *)fileSystem;
- S3_STORAGE *s3 = FS2S3(fileSystem);
int ret = 0;
+ S3FileSystem *fs = (S3FileSystem *)fileSystem;
+ S3Storage *s3 = FS2S3(fileSystem);
- /* Check if file exists in the cache. */
- *exist = S3CacheExists(fileSystem, name);
- if (*exist)
+ // Check if file exists in the cache.
+ *fileExists = S3CacheExists(fileSystem, name);
+ if (*fileExists) {
+ s3->log->LogDebugMessage("S3FileExists: Found file in cache.");
return (ret);
+ }
- /* It's not in the cache, try the S3 bucket. */
+ // It's not in the cache, try the S3 bucket.
+ size_t objectSize;
s3->statistics.objectExistsCount++;
- if ((ret = fs->connection->ObjectExists(name, *exist, objectSize)) != 0)
- s3->log->LogErrorMessage("S3Exist: ObjectExists request to S3 failed.");
+ if ((ret = fs->connection->ObjectExists(name, *fileExists, objectSize)) != 0)
+ s3->log->LogErrorMessage("S3FileExists: ObjectExists request to S3 failed.");
+ else
+ s3->log->LogDebugMessage("S3FileExists: Found file in S3.");
return (ret);
}
-/*
- * S3CacheExists --
- * Checks whether the given file exists in the cache.
- */
+// Checks whether the given file exists in the cache.
static bool
S3CacheExists(WT_FILE_SYSTEM *fileSystem, const std::string &name)
{
- const std::string path = S3Path(((S3_FILE_SYSTEM *)fileSystem)->cacheDir, name);
+ const std::string path = S3Path(((S3FileSystem *)fileSystem)->cacheDir, name);
return (LocalFileExists(path));
}
-/*
- * LocalFileExists --
- * Checks whether a file corresponding to the provided path exists locally.
- */
+// Checks whether a file corresponding to the provided path exists locally.
static bool
LocalFileExists(const std::string &path)
{
@@ -209,35 +197,44 @@ LocalFileExists(const std::string &path)
return (f.good());
}
-/*
- * S3GetDirectory --
- * Return a copy of a directory name after verifying that it is a directory.
- */
+// Return a copy of a directory name after verifying that it is a directory.
static int
-S3GetDirectory(const S3_STORAGE &s3, const std::string &home, const std::string &name, bool create,
+S3GetDirectory(const S3Storage &s3, const std::string &home, const std::string &name, bool create,
std::string &copy)
{
+ // copy must be initialised before the function returns.
copy = "";
- struct stat sb;
int ret;
std::string dirName;
- /* For relative pathnames, the path is considered to be relative to the home directory. */
+ // For relative pathnames, the path is considered to be relative to the home directory.
if (name[0] == '/')
dirName = name;
else
dirName = home + "/" + name;
- ret = stat(dirName.c_str(), &sb);
- if (ret != 0 && errno == ENOENT && create) {
- mkdir(dirName.c_str(), 0777);
- ret = stat(dirName.c_str(), &sb);
+ // Use filesystem status to find if directory exists.
+ std::error_code ec;
+ std::filesystem::file_status status = std::filesystem::status(dirName.c_str(), ec);
+
+ if (!std::filesystem::exists(status) && create) {
+ try {
+ std::filesystem::create_directory(dirName.c_str());
+ std::filesystem::permissions(dirName.c_str(), std::filesystem::perms::all);
+ } catch (std::filesystem::filesystem_error const &e) {
+ s3.log->LogErrorMessage(std::string("S3GetDirectory: ") + e.what());
+ }
+
+ s3.log->LogDebugMessage("S3GetDirectory: Successfully created directory.");
}
+
+ status = std::filesystem::status(dirName.c_str(), ec);
+ ret = ec.value();
+
if (ret != 0) {
- ret = errno;
s3.log->LogErrorMessage("S3GetDirectory: No such file or directory");
- } else if ((sb.st_mode & S_IFMT) != S_IFDIR) {
+ } else if (!std::filesystem::is_directory(status)) {
s3.log->LogErrorMessage("S3GetDirectory: invalid directory name");
ret = EINVAL;
}
@@ -246,29 +243,27 @@ S3GetDirectory(const S3_STORAGE &s3, const std::string &home, const std::string
return (ret);
}
-/*
- * S3FileClose --
- * File handle close.
- */
+// File handle close.
static int
S3FileClose(WT_FILE_HANDLE *fileHandle, WT_SESSION *session)
{
int ret = 0;
- S3_FILE_HANDLE *s3FileHandle = (S3_FILE_HANDLE *)fileHandle;
- S3_STORAGE *s3 = s3FileHandle->storage;
+ S3FileHandle *s3FileHandle = (S3FileHandle *)fileHandle;
+ S3Storage *s3 = s3FileHandle->storage;
WT_FILE_HANDLE *wtFileHandle = s3FileHandle->wtFileHandle;
- /*
- * We require exclusive access to the list of file handles when removing file handles. The
- * lock_guard will be unlocked automatically once the scope is exited.
- */
+
+ // We require exclusive access to the list of file handles when removing file handles. The
+ // lock_guard will be unlocked automatically once the scope is exited.
{
std::lock_guard<std::mutex> lock(s3->fhMutex);
s3->fhList.remove(s3FileHandle);
}
- if (wtFileHandle != NULL) {
+ if (wtFileHandle != nullptr) {
s3->statistics.fhOps++;
if ((ret = wtFileHandle->close(wtFileHandle, session)) != 0)
s3->log->LogErrorMessage("S3FileClose: close file handle failed.");
+ else
+ s3->log->LogDebugMessage("S3FileClose: Successfully closed file handle.");
}
free(s3FileHandle->iface.name);
@@ -276,91 +271,86 @@ S3FileClose(WT_FILE_HANDLE *fileHandle, WT_SESSION *session)
return (ret);
}
-/*
- * S3Open --
- * File open for the s3 storage source.
- */
+// File open for the s3 storage source.
static int
-S3Open(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name,
+S3FileOpen(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name,
WT_FS_OPEN_FILE_TYPE fileType, uint32_t flags, WT_FILE_HANDLE **fileHandlePtr)
{
- S3_FILE_HANDLE *s3FileHandle;
- S3_FILE_SYSTEM *fs = (S3_FILE_SYSTEM *)fileSystem;
- S3_STORAGE *s3 = fs->storage;
- WT_FILE_SYSTEM *wtFileSystem = fs->wtFileSystem;
- WT_FILE_HANDLE *wtFileHandle;
+ S3FileSystem *fs = (S3FileSystem *)fileSystem;
+ S3Storage *s3 = FS2S3(fileSystem);
int ret;
- *fileHandlePtr = NULL;
+ *fileHandlePtr = nullptr;
- /* We only support opening the file in read only mode. */
+ // We only support opening the file in read only mode.
if ((flags & WT_FS_OPEN_READONLY) == 0 || (flags & WT_FS_OPEN_CREATE) != 0) {
- s3->log->LogErrorMessage("S3Open: read-only access required.");
+ s3->log->LogErrorMessage("S3FileOpen: read-only access required.");
return (EINVAL);
}
- /*
- * Currently, only data files should be being opened; although this constraint can be relaxed in
- * the future.
- */
+ // Currently, only data files should be being opened; although this constraint can be relaxed in
+ // the future.
if (fileType != WT_FS_OPEN_FILE_TYPE_DATA && fileType != WT_FS_OPEN_FILE_TYPE_REGULAR) {
- s3->log->LogErrorMessage("S3Open: only data file and regular types supported.");
+ s3->log->LogErrorMessage("S3FileOpen: only data file and regular types supported.");
return (EINVAL);
}
- if ((s3FileHandle = (S3_FILE_HANDLE *)calloc(1, sizeof(S3_FILE_HANDLE))) == NULL) {
- s3->log->LogErrorMessage("S3Open: unable to allocate memory for file handle.");
+ S3FileHandle *s3FileHandle;
+ if ((s3FileHandle = (S3FileHandle *)calloc(1, sizeof(S3FileHandle))) == nullptr) {
+ s3->log->LogErrorMessage("S3FileOpen: unable to allocate memory for file handle.");
return (ENOMEM);
}
- /* Make a copy from S3 if the file is not in the cache. */
+ // Make a copy from S3 if the file is not in the cache.
const std::string cachePath = S3Path(fs->cacheDir, name);
if (!LocalFileExists(cachePath)) {
s3->statistics.getObjectCount++;
if ((ret = fs->connection->GetObject(name, cachePath)) != 0) {
- s3->log->LogErrorMessage("S3Open: GetObject request to S3 failed.");
+ s3->log->LogErrorMessage("S3FileOpen: GetObject request to S3 failed.");
return (ret);
}
}
- /* Use WiredTiger's native file handle open. */
+ // Use WiredTiger's native file handle open.
+ WT_FILE_SYSTEM *wtFileSystem = fs->wtFileSystem;
+ WT_FILE_HANDLE *wtFileHandle;
ret = wtFileSystem->fs_open_file(
wtFileSystem, session, cachePath.c_str(), fileType, flags, &wtFileHandle);
if (ret != 0) {
- s3->log->LogErrorMessage("S3Open: fs_open_file failed.");
+ s3->log->LogErrorMessage("S3FileOpen: fs_open_file failed.");
return (ret);
- }
+ } else
+ s3->log->LogDebugMessage("S3FileOpen: fs_open_file succeeded.");
s3FileHandle->wtFileHandle = wtFileHandle;
s3FileHandle->storage = s3;
+ // We only define the functions we need since S3 is read-only.
WT_FILE_HANDLE *fileHandle = (WT_FILE_HANDLE *)s3FileHandle;
fileHandle->close = S3FileClose;
- fileHandle->fh_advise = NULL;
- fileHandle->fh_extend = NULL;
- fileHandle->fh_extend_nolock = NULL;
+ fileHandle->fh_advise = nullptr;
+ fileHandle->fh_extend = nullptr;
+ fileHandle->fh_extend_nolock = nullptr;
fileHandle->fh_lock = S3FileLock;
- fileHandle->fh_map = NULL;
- fileHandle->fh_map_discard = NULL;
- fileHandle->fh_map_preload = NULL;
- fileHandle->fh_unmap = NULL;
+ fileHandle->fh_map = nullptr;
+ fileHandle->fh_map_discard = nullptr;
+ fileHandle->fh_map_preload = nullptr;
+ fileHandle->fh_unmap = nullptr;
fileHandle->fh_read = S3FileRead;
fileHandle->fh_size = S3FileSize;
- fileHandle->fh_sync = NULL;
- fileHandle->fh_sync_nowait = NULL;
- fileHandle->fh_truncate = NULL;
- fileHandle->fh_write = NULL;
+ fileHandle->fh_sync = nullptr;
+ fileHandle->fh_sync_nowait = nullptr;
+ fileHandle->fh_truncate = nullptr;
+ fileHandle->fh_write = nullptr;
fileHandle->name = strdup(name);
- if (fileHandle->name == NULL) {
- s3->log->LogErrorMessage("S3Open: unable to allocate memory for object name.");
+ if (fileHandle->name == nullptr) {
+ s3->log->LogErrorMessage("S3FileOpen: unable to allocate memory for object name.");
return (ENOMEM);
}
- /*
- * We require exclusive access to the list of file handles when adding file handles to it. The
- * lock_guard will be unlocked automatically when the scope is exited.
- */
+ // We require exclusive access to the list of file handles when adding file handles to it. The
+ // lock_guard will be unlocked automatically when the scope is exited.
{
std::lock_guard<std::mutex> lock(s3->fhMutex);
s3FileHandle->storage->fhList.push_back(s3FileHandle);
@@ -370,157 +360,141 @@ S3Open(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name,
return (0);
}
-/*
- * S3Rename --
- * POSIX rename, not supported for cloud objects.
- */
+// POSIX rename, not supported for cloud objects.
static int
S3Rename(WT_FILE_SYSTEM *file_system, WT_SESSION *session, const char *from, const char *to,
uint32_t flags)
{
- S3_STORAGE *s3 = FS2S3(file_system);
+ S3Storage *s3 = FS2S3(file_system);
- (void)to; /* unused */
- (void)flags; /* unused */
+ UNUSED(to);
+ UNUSED(flags);
s3->log->LogErrorMessage(std::string(from) + ": rename of file not supported");
return (ENOTSUP);
}
-/*
- * S3Remove --
- * POSIX remove, not supported for cloud objects.
- */
+// POSIX remove, not supported for cloud objects.
static int
S3Remove(WT_FILE_SYSTEM *file_system, WT_SESSION *session, const char *name, uint32_t flags)
{
- S3_STORAGE *s3 = FS2S3(file_system);
+ S3Storage *s3 = FS2S3(file_system);
- (void)flags; /* unused */
+ UNUSED(flags);
s3->log->LogErrorMessage(std::string(name) + ": remove of file not supported");
return (ENOTSUP);
}
-/*
- * S3Size --
- * Get the size of a file in bytes, by file name.
- */
+// Get the size of a file in bytes, by file name.
+
static int
-S3Size(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name, wt_off_t *sizep)
+S3ObjectSize(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name, wt_off_t *sizep)
{
- S3_STORAGE *s3 = FS2S3(fileSystem);
- size_t objectSize;
- bool exist;
+ // sizep must be initialised before the function returns.
*sizep = 0;
+
+ S3Storage *s3 = FS2S3(fileSystem);
+ S3FileSystem *fs = (S3FileSystem *)fileSystem;
+ size_t objectSize;
+ bool exists;
int ret;
- S3_FILE_SYSTEM *fs = (S3_FILE_SYSTEM *)fileSystem;
s3->statistics.objectExistsCount++;
- if ((ret = fs->connection->ObjectExists(name, exist, objectSize)) != 0)
+ if ((ret = fs->connection->ObjectExists(name, exists, objectSize)) != 0) {
+ s3->log->LogDebugMessage(
+ "S3ObjectSize: Found S3 object size to be " + std::to_string(objectSize) + " bytes.");
return (ret);
+ }
*sizep = objectSize;
return (ret);
}
-/*
- * S3FileLock --
- * Lock/unlock a file.
- */
+// Lock/unlock a file.
static int
S3FileLock(WT_FILE_HANDLE *fileHandle, WT_SESSION *session, bool lock)
{
- /* Locks are always granted. */
- (void)session; /* Unused */
- (void)lock; /* Unused */
+ // Locks are always granted.
+ UNUSED(session);
+ UNUSED(lock);
- ((S3_FILE_HANDLE *)fileHandle)->storage->statistics.fhOps++;
return (0);
}
-/*
- * S3FileRead --
- * Read a file using WiredTiger's native file handle read.
- */
+// Read a file using WiredTiger's native file handle read.
+
static int
S3FileRead(WT_FILE_HANDLE *fileHandle, WT_SESSION *session, wt_off_t offset, size_t len, void *buf)
{
- S3_FILE_HANDLE *s3FileHandle = (S3_FILE_HANDLE *)fileHandle;
- S3_STORAGE *s3 = s3FileHandle->storage;
+ S3FileHandle *s3FileHandle = (S3FileHandle *)fileHandle;
+ S3Storage *s3 = s3FileHandle->storage;
WT_FILE_HANDLE *wtFileHandle = s3FileHandle->wtFileHandle;
int ret;
s3->statistics.fhReadOps++;
if ((ret = wtFileHandle->fh_read(wtFileHandle, session, offset, len, buf)) != 0)
s3->log->LogErrorMessage("S3FileRead: fh_read failed.");
+ else
+ s3->log->LogDebugMessage(
+ "S3FileRead: fh_read succeeded in reading " + std::to_string(len) + " bytes.");
return (ret);
}
-/*
- * S3FileSize --
- * Get the size of a file in bytes, by file handle.
- */
+// Get the size of a file in bytes, by file handle.
static int
S3FileSize(WT_FILE_HANDLE *fileHandle, WT_SESSION *session, wt_off_t *sizep)
{
- S3_FILE_HANDLE *s3FileHandle = (S3_FILE_HANDLE *)fileHandle;
- S3_STORAGE *s3 = s3FileHandle->storage;
+ S3FileHandle *s3FileHandle = (S3FileHandle *)fileHandle;
+ S3Storage *s3 = s3FileHandle->storage;
WT_FILE_HANDLE *wtFileHandle = s3FileHandle->wtFileHandle;
s3->statistics.fhOps++;
return (wtFileHandle->fh_size(wtFileHandle, session, sizep));
}
-/*
- * S3CustomizeFileSystem --
- * Return a customized file system to access the s3 storage source objects. The authToken
- * contains the AWS access key ID and the AWS secret key as comma-separated values.
- */
+// Return a customized file system to access the s3 storage source objects. The authToken
+// contains the AWS access key ID and the AWS secret key as comma-separated values.
static int
S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, const char *bucket,
const char *authToken, const char *config, WT_FILE_SYSTEM **fileSystem)
{
- S3_FILE_SYSTEM *fs;
- WT_FILE_SYSTEM *wtFileSystem;
- S3_STORAGE *s3;
+ S3Storage *s3;
int ret;
- std::string cacheDir;
- s3 = (S3_STORAGE *)storageSource;
+ s3 = (S3Storage *)storageSource;
+
+ // We need to have a bucket to setup the file system. The bucket is expected to be a name and a
+ // region, separated by a semi-colon. eg: 'abcd;ap-southeast-2'.
- /*
- * We need to have a bucket to setup the file system. The bucket is expected to be a name and a
- * region, separated by a semi-colon. eg: 'abcd;ap-southeast-2'.
- */
- if (bucket == NULL || strlen(bucket) == 0) {
+ if (bucket == nullptr || strlen(bucket) == 0) {
s3->log->LogErrorMessage("S3CustomizeFileSystem: bucket not specified.");
return (EINVAL);
}
int delimiter = std::string(bucket).find(';');
if (delimiter == std::string::npos || delimiter == 0 || delimiter == strlen(bucket) - 1) {
s3->log->LogErrorMessage(
- "S3CustomizeFileSystem: bucket malformed, "
- "should be a name and a region separated by a semi-colon.");
+ "S3CustomizeFileSystem: improper bucket name, "
+ "should be a name and a region separated by a semicolon.");
return (EINVAL);
}
const std::string bucketName = std::string(bucket).substr(0, delimiter);
const std::string region = std::string(bucket).substr(delimiter + 1);
- /* Fail if there is no authentication provided. */
- if (authToken == NULL || strlen(authToken) == 0) {
+ // Fail if there is no authentication provided.
+ if (authToken == nullptr || strlen(authToken) == 0) {
s3->log->LogErrorMessage("S3CustomizeFileSystem: authToken not specified.");
return (EINVAL);
}
- /*
- * An auth token is needed to setup the file system. The token is expected to be an access key
- * and a secret key separated by a semi-colon.
- */
- if (authToken == NULL || strlen(authToken) == 0) {
+ // An auth token is needed to setup the file system. The token is expected to be an access key
+ // and a secret key separated by a semi-colon.
+ if (authToken == nullptr || strlen(authToken) == 0) {
s3->log->LogErrorMessage("S3CustomizeFileSystem: auth token not specified.");
return (EINVAL);
}
delimiter = std::string(authToken).find(';');
if (delimiter == std::string::npos || delimiter == 0 || delimiter == strlen(authToken) - 1) {
- s3->log->LogErrorMessage("S3CustomizeFileSystem: authToken malformed.");
+ s3->log->LogErrorMessage(
+ "S3CustomizeFileSystem: improper authToken, should be an access key and a secret key "
+ "separated by a semicolon.");
return (EINVAL);
}
const std::string accessKeyId = std::string(authToken).substr(0, delimiter);
@@ -530,11 +504,12 @@ S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, con
credentials.SetAWSAccessKeyId(accessKeyId);
credentials.SetAWSSecretKey(secretKey);
- /*
- * Parse configuration string.
- */
+ s3->log->LogDebugMessage(
+ "S3CustomizeFileSystem: AWS access key and secret key set successfully.");
- /* Get any prefix to be used for the object keys. */
+ // Parse configuration string.
+
+ // Get any prefix to be used for the object keys.
WT_CONFIG_ITEM objPrefixConf;
std::string objPrefix;
if ((ret = s3->wtApi->config_get_string(
@@ -545,18 +520,17 @@ S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, con
return (ret);
}
- /* Configure the AWS Client configuration. */
+ // Configure the AWS Client configuration.
Aws::S3Crt::ClientConfiguration awsConfig;
awsConfig.partSize = partSize;
awsConfig.region = region;
awsConfig.throughputTargetGbps = throughputTargetGbps;
- /*
- * Get the directory to setup the cache, or use the default one. The default cache directory is
- * named "cache-<name>", where name is the last component of the bucket name's path. We'll
- * create it if it doesn't exist.
- */
+ // Get the directory to setup the cache, or use the default one. The default cache directory is
+ // named "cache-<name>", where name is the last component of the bucket name's path. We'll
+ // create it if it doesn't exist.
WT_CONFIG_ITEM cacheDirConf;
+ std::string cacheDir;
std::string cacheStr;
if ((ret = s3->wtApi->config_get_string(
s3->wtApi, session, config, "cache_directory", &cacheDirConf)) == 0)
@@ -566,21 +540,23 @@ S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, con
ret = 0;
} else {
s3->log->LogErrorMessage(
- "wiredtiger_extension_init: error parsing config for cache directory.");
+ "S3CustomizeFileSystem: error parsing config for cache directory.");
return (ret);
}
- /* Fetch the native WT file system. */
+ // Fetch the native WT file system.
+ WT_FILE_SYSTEM *wtFileSystem;
if ((ret = s3->wtApi->file_system_get(s3->wtApi, session, &wtFileSystem)) != 0)
return (ret);
- /* Get a copy of the home and cache directory. */
+ // Get a copy of the home and cache directory.
const std::string homeDir = session->connection->get_home(session->connection);
if ((ret = S3GetDirectory(*s3, homeDir, cacheStr, true, cacheDir)) != 0)
return (ret);
- /* Create the file system. */
- if ((fs = (S3_FILE_SYSTEM *)calloc(1, sizeof(S3_FILE_SYSTEM))) == NULL) {
+ // Create the file system.
+ S3FileSystem *fs;
+ if ((fs = (S3FileSystem *)calloc(1, sizeof(S3FileSystem))) == nullptr) {
s3->log->LogErrorMessage(
"S3CustomizeFileSystem: unable to allocate memory for file system.");
return (ENOMEM);
@@ -590,7 +566,6 @@ S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, con
fs->homeDir = homeDir;
fs->cacheDir = cacheDir;
- /* New can fail; will deal with this later. */
try {
fs->connection = new S3Connection(credentials, awsConfig, bucketName, objPrefix);
} catch (std::invalid_argument &e) {
@@ -601,13 +576,15 @@ S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, con
fs->fileSystem.fs_directory_list_single = S3ObjectListSingle;
fs->fileSystem.fs_directory_list_free = S3ObjectListFree;
fs->fileSystem.terminate = S3FileSystemTerminate;
- fs->fileSystem.fs_exist = S3Exist;
- fs->fileSystem.fs_open_file = S3Open;
+ fs->fileSystem.fs_exist = S3FileExists;
+ fs->fileSystem.fs_open_file = S3FileOpen;
fs->fileSystem.fs_remove = S3Remove;
fs->fileSystem.fs_rename = S3Rename;
- fs->fileSystem.fs_size = S3Size;
+ fs->fileSystem.fs_size = S3ObjectSize;
- /* Add to the list of the active file systems. Lock will be freed when the scope is exited. */
+ s3->log->LogDebugMessage("S3CustomizeFileSystem: S3 connection established.");
+
+ // Add to the list of the active file systems. Lock will be freed when the scope is exited.
{
std::lock_guard<std::mutex> lockGuard(s3->fsListMutex);
s3->fsList.push_back(fs);
@@ -617,19 +594,16 @@ S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, con
return (ret);
}
-/*
- * S3FileSystemTerminate --
- * Discard any resources on termination of the file system.
- */
+// Discard any resources on termination of the file system.
static int
S3FileSystemTerminate(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session)
{
- S3_FILE_SYSTEM *fs = (S3_FILE_SYSTEM *)fileSystem;
- S3_STORAGE *s3 = fs->storage;
+ S3FileSystem *fs = (S3FileSystem *)fileSystem;
+ S3Storage *s3 = FS2S3(fileSystem);
- UNUSED(session); /* unused */
+ UNUSED(session);
- /* Remove from the active filesystems list. The lock will be freed when the scope is exited. */
+ // Remove from the active filesystems list. The lock will be freed when the scope is exited.
{
std::lock_guard<std::mutex> lockGuard(s3->fsListMutex);
s3->fsList.remove(fs);
@@ -640,90 +614,70 @@ S3FileSystemTerminate(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session)
return (0);
}
-/*
- * S3ObjectList --
- * Return a list of object names for the given location.
- */
+// Return a list of object names for the given location.
static int
-S3ObjectList(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *directory,
- const char *prefix, char ***objectList, uint32_t *count)
+S3ObjectListInternal(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *directory,
+ const char *prefix, char ***objectList, uint32_t *count, bool listSingle)
{
- S3_FILE_SYSTEM *fs = (S3_FILE_SYSTEM *)fileSystem;
- S3_STORAGE *s3 = FS2S3(fileSystem);
-
+ S3FileSystem *fs = (S3FileSystem *)fileSystem;
+ S3Storage *s3 = FS2S3(fileSystem);
std::vector<std::string> objects;
std::string completePrefix;
- if (directory != NULL) {
+ *count = 0;
+
+ if (directory != nullptr) {
completePrefix += directory;
- /* Add a terminating '/' if one doesn't exist. */
+ // Add a terminating '/' if one doesn't exist.
if (completePrefix.length() > 1 && completePrefix[completePrefix.length() - 1] != '/')
completePrefix += '/';
}
- if (prefix != NULL)
+ if (prefix != nullptr)
completePrefix += prefix;
int ret;
s3->statistics.listObjectsCount++;
- if ((ret = fs->connection->ListObjects(completePrefix, objects)) != 0) {
+
+ ret = listSingle ? fs->connection->ListObjects(completePrefix, objects, 1, true) :
+ fs->connection->ListObjects(completePrefix, objects);
+
+ if (ret != 0) {
s3->log->LogErrorMessage("S3ObjectList: ListObjects request to S3 failed.");
return (ret);
}
*count = objects.size();
+ s3->log->LogDebugMessage("S3ObjectList: ListObjects request to S3 succeeded. Received " +
+ std::to_string(*count) + " objects.");
S3ObjectListAdd(*s3, objectList, objects, *count);
return (ret);
}
-/*
- * S3ObjectListSingle --
- * Return a single object name for the given location.
- */
+// Return a list of object names for the given location.
static int
-S3ObjectListSingle(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *directory,
+S3ObjectList(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *directory,
const char *prefix, char ***objectList, uint32_t *count)
{
- S3_FILE_SYSTEM *fs = (S3_FILE_SYSTEM *)fileSystem;
- S3_STORAGE *s3 = FS2S3(fileSystem);
-
- std::vector<std::string> objects;
- std::string completePrefix;
-
- if (directory != NULL) {
- completePrefix += directory;
- /* Add a terminating '/' if one doesn't exist. */
- if (completePrefix.length() > 1 && completePrefix[completePrefix.length() - 1] != '/')
- completePrefix += '/';
- }
- if (prefix != NULL)
- completePrefix += prefix;
-
- int ret;
- s3->statistics.listObjectsCount++;
- if ((ret = fs->connection->ListObjects(completePrefix, objects, 1, true)) != 0) {
- s3->log->LogErrorMessage("S3ObjectListSingle: ListObjects request to S3 failed.");
- return (ret);
- }
-
- *count = objects.size();
-
- S3ObjectListAdd(*s3, objectList, objects, *count);
+ return (S3ObjectListInternal(fileSystem, session, directory, prefix, objectList, count, false));
+}
- return (ret);
+// Return a single object name for the given location.
+static int
+S3ObjectListSingle(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *directory,
+ const char *prefix, char ***objectList, uint32_t *count)
+{
+ return (S3ObjectListInternal(fileSystem, session, directory, prefix, objectList, count, true));
}
-/*
- * S3ObjectListFree --
- * Free memory allocated by S3ObjectList.
- */
+// Free memory allocated by S3ObjectList.
static int
S3ObjectListFree(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, char **objectList, uint32_t count)
{
UNUSED(fileSystem);
UNUSED(session);
- if (objectList != NULL) {
+ if (objectList != nullptr) {
while (count > 0)
free(objectList[--count]);
free(objectList);
@@ -732,22 +686,19 @@ S3ObjectListFree(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, char **objectL
return (0);
}
-/*
- * S3ObjectListAdd --
- * Add objects retrieved from S3 bucket into the object list, and allocate the memory needed.
- */
+// Add objects retrieved from S3 bucket into the object list, and allocate the memory needed.
static int
-S3ObjectListAdd(const S3_STORAGE &s3, char ***objectList, const std::vector<std::string> &objects,
+S3ObjectListAdd(const S3Storage &s3, char ***objectList, const std::vector<std::string> &objects,
const uint32_t count)
{
char **entries;
- if ((entries = (char **)malloc(sizeof(char *) * count)) == NULL) {
+ if ((entries = (char **)malloc(sizeof(char *) * count)) == nullptr) {
s3.log->LogErrorMessage("S3ObjectListAdd: unable to allocate memory for object list.");
return (ENOMEM);
}
for (int i = 0; i < count; i++) {
- if ((entries[i] = strdup(objects[i].c_str())) == NULL) {
+ if ((entries[i] = strdup(objects[i].c_str())) == nullptr) {
s3.log->LogErrorMessage(
"S3ObjectListAdd: unable to allocate memory for object string.");
return (ENOMEM);
@@ -758,15 +709,12 @@ S3ObjectListAdd(const S3_STORAGE &s3, char ***objectList, const std::vector<std:
return (0);
}
-/*
- * S3AddReference --
- * Add a reference to the storage source so we can reference count to know when to really
- * terminate.
- */
+// Add a reference to the storage source so we can reference count to know when to really
+// terminate.
static int
S3AddReference(WT_STORAGE_SOURCE *storageSource)
{
- S3_STORAGE *s3 = (S3_STORAGE *)storageSource;
+ S3Storage *s3 = (S3Storage *)storageSource;
if (s3->referenceCount == 0 || s3->referenceCount + 1 == 0) {
s3->log->LogErrorMessage("S3AddReference: missing reference or overflow.");
@@ -777,64 +725,55 @@ S3AddReference(WT_STORAGE_SOURCE *storageSource)
return (0);
}
-/*
- * S3Terminate --
- * Discard any resources on termination.
- */
+// Discard any resources on termination.
+
static int
S3Terminate(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session)
{
- S3_STORAGE *s3 = (S3_STORAGE *)storageSource;
+ S3Storage *s3 = (S3Storage *)storageSource;
if (--s3->referenceCount != 0)
return (0);
- /*
- * Is it currently unclear at the moment what the multi-threading will look like in the
- * extension. The current implementation is NOT thread-safe, and needs to be addressed in the
- * future, as mulitple threads could call terminate leading to a race condition.
- */
+ // It is currently unclear at the moment what the multi-threading will look like in the
+ // extension. The current implementation is NOT thread-safe, and needs to be addressed in the
+ // future, as multiple threads could call terminate leading to a race condition.
while (!s3->fhList.empty()) {
- S3_FILE_HANDLE *fs = s3->fhList.front();
+ S3FileHandle *fs = s3->fhList.front();
S3FileClose((WT_FILE_HANDLE *)fs, session);
}
- /*
- * Terminate any active filesystems. There are no references to the storage source, so it is
- * safe to walk the active filesystem list without a lock. The removal from the list happens
- * under a lock. Also, removal happens from the front and addition at the end, so we are safe.
- */
+
+ // Terminate any active filesystems. There are no references to the storage source, so it is
+ // safe to walk the active filesystem list without a lock. The removal from the list happens
+ // under a lock. Also, removal happens from the front and addition at the end, so we are safe.
while (!s3->fsList.empty()) {
- S3_FILE_SYSTEM *fs = s3->fsList.front();
+ S3FileSystem *fs = s3->fsList.front();
S3FileSystemTerminate(&fs->fileSystem, session);
}
- /* Log collected statistics on termination. */
- S3ShowStatistics(*s3);
+ S3LogStatistics(*s3);
Aws::Utils::Logging::ShutdownAWSLogging();
Aws::ShutdownAPI(options);
+ s3->log->LogDebugMessage("S3Terminate: Terminated S3 storage source.");
delete (s3);
return (0);
}
-/*
- * S3Flush --
- * Flush file to S3 Store using AWS SDK C++ PutObject.
- */
+// Flush file to S3 Store using AWS SDK C++ PutObject.
static int
S3Flush(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, WT_FILE_SYSTEM *fileSystem,
const char *source, const char *object, const char *config)
{
- S3_STORAGE *s3 = (S3_STORAGE *)storageSource;
- S3_FILE_SYSTEM *fs = (S3_FILE_SYSTEM *)fileSystem;
+ S3Storage *s3 = (S3Storage *)storageSource;
+ S3FileSystem *fs = (S3FileSystem *)fileSystem;
WT_FILE_SYSTEM *wtFileSystem = fs->wtFileSystem;
-
int ret;
bool nativeExist;
FS2S3(fileSystem)->statistics.putObjectCount++;
- /* Confirm that the file exists on the native filesystem. */
+ // Confirm that the file exists on the native filesystem.
if ((ret = wtFileSystem->fs_exist(wtFileSystem, session, source, &nativeExist)) != 0) {
s3->log->LogErrorMessage("S3Flush: Failed to check for the existence of " +
std::string(source) + " on the native filesystem.");
@@ -845,29 +784,30 @@ S3Flush(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, WT_FILE_SYSTEM *f
return (ENOENT);
}
- /* Upload the object into the bucket. */
+ // Upload the object into the bucket.
if (ret = (fs->connection->PutObject(object, source)) != 0)
s3->log->LogErrorMessage("S3Flush: PutObject request to S3 failed.");
+ else
+ s3->log->LogDebugMessage("S3Flush: Uploaded object to S3.");
return (ret);
}
-/*
- * S3FlushFinish --
- * Flush local file to cache.
- */
+// Flush local file to cache.
static int
S3FlushFinish(WT_STORAGE_SOURCE *storage, WT_SESSION *session, WT_FILE_SYSTEM *fileSystem,
const char *source, const char *object, const char *config)
{
- S3_STORAGE *s3 = (S3_STORAGE *)storage;
- S3_FILE_SYSTEM *fs = (S3_FILE_SYSTEM *)fileSystem;
- /* Constructing the pathname for source and cache from file system and local. */
+ S3Storage *s3 = (S3Storage *)storage;
+ S3FileSystem *fs = (S3FileSystem *)fileSystem;
+ // Constructing the pathname for source and cache from file system and local.
std::string srcPath = S3Path(fs->homeDir, source);
std::string destPath = S3Path(fs->cacheDir, object);
- /* Linking file with the local file. */
- int ret = link(srcPath.c_str(), destPath.c_str());
+ // Linking file with the local file.
+ std::error_code ec;
+ std::filesystem::create_hard_link(srcPath.c_str(), destPath.c_str(), ec);
+ int ret = ec.value();
if (ret != 0) {
ret = errno;
s3->log->LogErrorMessage(
@@ -875,21 +815,22 @@ S3FlushFinish(WT_STORAGE_SOURCE *storage, WT_SESSION *session, WT_FILE_SYSTEM *f
return (ret);
}
- /* The file should be read-only. */
- ret = chmod(destPath.c_str(), 0444);
+ // The file should be read-only.
+ std::filesystem::permissions(destPath.c_str(),
+ std::filesystem::perms::owner_read | std::filesystem::perms::group_read |
+ std::filesystem::perms::others_read,
+ std::filesystem::perm_options::add, ec);
+ ret = ec.value();
if (ret != 0) {
ret = errno;
- s3->log->LogErrorMessage("S3FlushFinish: chmod of " + destPath + " failed");
+ s3->log->LogErrorMessage("S3FlushFinish: read permissions of " + destPath + " failed");
}
return (ret);
}
-/*
- * S3ShowStatistics --
- * Log collected statistics.
- */
+// Log collected statistics.
static void
-S3ShowStatistics(const S3_STORAGE &s3)
+S3LogStatistics(const S3Storage &s3)
{
s3.log->LogDebugMessage(
"S3 list objects count: " + std::to_string(s3.statistics.listObjectsCount));
@@ -904,28 +845,19 @@ S3ShowStatistics(const S3_STORAGE &s3)
"File handle read operations: " + std::to_string(s3.statistics.fhReadOps));
}
-/*
- * wiredtiger_extension_init --
- * A S3 storage source library.
- */
+// A S3 storage source library.
int
wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
{
- S3_STORAGE *s3;
- S3_FILE_SYSTEM *fs;
+ S3Storage *s3;
WT_CONFIG_ITEM v;
- /* No error handling for now. */
- s3 = new S3_STORAGE;
-
+ s3 = new S3Storage;
s3->wtApi = connection->get_extension_api(connection);
+ int ret = s3->wtApi->config_get(s3->wtApi, nullptr, config, "verbose.tiered", &v);
- int ret = s3->wtApi->config_get(s3->wtApi, NULL, config, "verbose", &v);
-
- /*
- * Create a logger for the storage source. Verbose level defaults to WT_VERBOSE_ERROR (-3) if it
- * is outside the valid range or not found.
- */
+ // Create a logger for the storage source. Verbose level defaults to WT_VERBOSE_ERROR (-3) if it
+ // is outside the valid range or not found.
s3->verbose = WT_VERBOSE_ERROR;
s3->log = Aws::MakeShared<S3LogSystem>("storage", s3->wtApi, s3->verbose);
@@ -939,32 +871,33 @@ wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
return (ret != 0 ? ret : EINVAL);
}
- /* Set up statistics. */
+ // Set up statistics.
s3->statistics = {0};
- /* Initialize the AWS SDK. */
+ // Initialize the AWS SDK.
Aws::Utils::Logging::InitializeAWSLogging(s3->log);
Aws::InitAPI(options);
- /*
- * Allocate a S3 storage structure, with a WT_STORAGE structure as the first field, allowing us
- * to treat references to either type of structure as a reference to the other type.
- */
+ // Allocate a S3 storage structure, with a WT_STORAGE structure as the first field, allowing us
+ // to treat references to either type of structure as a reference to the other type.
s3->storageSource.ss_customize_file_system = S3CustomizeFileSystem;
s3->storageSource.ss_add_reference = S3AddReference;
s3->storageSource.terminate = S3Terminate;
s3->storageSource.ss_flush = S3Flush;
s3->storageSource.ss_flush_finish = S3FlushFinish;
- /*
- * The first reference is implied by the call to add_storage_source.
- */
+ // The first reference is implied by the call to add_storage_source.
s3->referenceCount = 1;
- /* Load the storage */
- if ((ret = connection->add_storage_source(connection, "s3_store", &s3->storageSource, NULL)) !=
- 0)
+ // Load the storage
+ if ((ret = connection->add_storage_source(
+ connection, "s3_store", &s3->storageSource, nullptr)) != 0) {
+ s3->log->LogErrorMessage(
+ "wiredtiger_extension_init: Could not load S3 storage source, shutting down.");
+ Aws::Utils::Logging::ShutdownAWSLogging();
+ Aws::ShutdownAPI(options);
delete (s3);
+ }
return (ret);
}
diff --git a/src/third_party/wiredtiger/ext/storage_sources/s3_store/test/test_s3_connection.cpp b/src/third_party/wiredtiger/ext/storage_sources/s3_store/test/test_s3_connection.cpp
index 5440edfd59d..c93fc492c10 100644
--- a/src/third_party/wiredtiger/ext/storage_sources/s3_store/test/test_s3_connection.cpp
+++ b/src/third_party/wiredtiger/ext/storage_sources/s3_store/test/test_s3_connection.cpp
@@ -1,12 +1,39 @@
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
#include <s3_connection.h>
#include <fstream>
#include <random>
-/* Default config settings for the Test environment. */
+// Default config settings for the Test environment.
namespace TestDefaults {
const Aws::String region = Aws::Region::AP_SOUTHEAST_2;
const double throughputTargetGbps = 5;
-const uint64_t partSize = 8 * 1024 * 1024; /* 8 MB. */
+const uint64_t partSize = 8 * 1024 * 1024; // 8 MB.
static std::string bucketName("s3testext"); // Can be overridden with environment variables.
static std::string objPrefix("s3test_artefacts--unit_"); // To be concatenated with a random string.
} // namespace TestDefaults
@@ -19,7 +46,7 @@ int TestGetObject(const Aws::S3Crt::ClientConfiguration &config);
int TestObjectExists(const Aws::S3Crt::ClientConfiguration &config);
int TestBadBucket(const Aws::S3Crt::ClientConfiguration &config);
-/* Wrapper for unit test functions. */
+// Wrapper for unit test functions.
#define TEST(func, config) \
do { \
int __ret; \
@@ -27,11 +54,8 @@ int TestBadBucket(const Aws::S3Crt::ClientConfiguration &config);
return (__ret); \
} while (0)
-/*
- * randomizeTestPrefix --
- * Concatenates a random suffix to the prefix being used for the test object keys. Example of
- * generated test prefix: "s3test_artefacts/unit_" 2022-31-01-16-34-10_623843294/"
- */
+// Concatenates a random suffix to the prefix being used for the test object keys. Example of
+// generated test prefix: "s3test_artefacts/unit_" 2022-31-01-16-34-10_623843294/"
static int
randomizeTestPrefix()
{
@@ -43,7 +67,7 @@ randomizeTestPrefix()
TestDefaults::objPrefix += timeStr;
- /* Create a random device and use it to generate a random seed to initialize the generator. */
+ // Create a random device and use it to generate a random seed to initialize the generator.
std::random_device myRandomDevice;
unsigned seed = myRandomDevice();
std::default_random_engine myRandomEngine(seed);
@@ -54,20 +78,17 @@ randomizeTestPrefix()
return (TEST_SUCCESS);
}
-/*
- * setupTestDefaults --
- * Override the defaults with the ones specific for this test instance.
- */
+// Overrides the defaults with the ones specific for this test instance.
static int
setupTestDefaults()
{
- /* Prefer to use the bucket provided through the environment variable. */
+ // Prefer to use the bucket provided through the environment variable.
const char *envBucket = std::getenv("WT_S3_EXT_BUCKET");
- if (envBucket != NULL)
+ if (envBucket != nullptr)
TestDefaults::bucketName = envBucket;
std::cerr << "Bucket to be used for testing: " << TestDefaults::bucketName << std::endl;
- /* Append the prefix to be used for object names by a unique string. */
+ // Append the prefix to be used for object names by a unique string.
if (randomizeTestPrefix() != 0)
return (TEST_FAILURE);
std::cerr << "Generated prefix: " << TestDefaults::objPrefix << std::endl;
@@ -79,7 +100,7 @@ static int
CleanupTestListObjects(S3Connection &conn, const int totalObjects, const std::string &prefix,
const std::string &fileName)
{
- /* Delete objects and file at end of test. */
+ // Delete objects and file at end of test.
int ret = 0;
for (int i = 0; i < totalObjects; i++) {
if ((ret = conn.DeleteObject(prefix + std::to_string(i) + ".txt")) != 0)
@@ -92,50 +113,47 @@ CleanupTestListObjects(S3Connection &conn, const int totalObjects, const std::st
return (ret);
}
-/*
- * TestListObjects --
- * Unit test for listing S3 objects under the test bucket.
- */
-/* Todo: Remove code duplication in this function. */
+// Lists S3 objects under the test bucket.
+// Todo: Remove code duplication in this function.
int
TestListObjects(const Aws::S3Crt::ClientConfiguration &config)
{
S3Connection conn(config, TestDefaults::bucketName, TestDefaults::objPrefix);
std::vector<std::string> objects;
- /* Name of file to insert in the test. */
+ // Name of file to insert in the test.
const std::string fileName = "test_list_objects.txt";
- /* Total objects to insert in the test. */
+ // Total objects to insert in the test.
const int32_t totalObjects = 20;
- /* Prefix for objects in this test. */
+ // Prefix for objects in this test.
const std::string prefix = "test_list_objects_";
- /* Parameter for getting single object. */
+ // Parameter for getting single object.
const bool listSingle = true;
- /* Number of objects to access per iteration of AWS. */
+ // Number of objects to access per iteration of AWS.
int32_t batchSize = 1;
- /* Expected number of matches. */
+ // Expected number of matches.
int32_t expectedResult = 0;
int ret;
- /* No matching objects. */
+ // No matching objects.
if ((ret = conn.ListObjects(prefix, objects)) != 0)
return (ret);
if (objects.size() != expectedResult)
return (TEST_FAILURE);
- /* No matching objects with listSingle. */
+ // No matching objects with listSingle.
if ((ret = conn.ListObjects(prefix, objects, batchSize, listSingle)) != 0)
return (ret);
if (objects.size() != expectedResult)
return (TEST_FAILURE);
- /* Create file to prepare for test. */
+ // Create file to prepare for test.
if (!static_cast<bool>(std::ofstream(fileName).put('.'))) {
std::cerr << "Error creating file." << std::endl;
return (TEST_FAILURE);
}
- /* Put objects to prepare for test. */
+ // Put objects to prepare for test.
for (int i = 0; i < totalObjects; i++) {
if ((ret = conn.PutObject(prefix + std::to_string(i) + ".txt", fileName)) != 0) {
CleanupTestListObjects(conn, i, prefix, fileName);
@@ -143,7 +161,7 @@ TestListObjects(const Aws::S3Crt::ClientConfiguration &config)
}
}
- /* List all objects. */
+ // List all objects.
expectedResult = totalObjects;
if ((ret = conn.ListObjects(prefix, objects)) != 0) {
CleanupTestListObjects(conn, totalObjects, prefix, fileName);
@@ -154,7 +172,7 @@ TestListObjects(const Aws::S3Crt::ClientConfiguration &config)
return (TEST_FAILURE);
}
- /* List single. */
+ // List single.
objects.clear();
expectedResult = 1;
if ((ret = conn.ListObjects(prefix, objects, batchSize, listSingle)) != 0) {
@@ -166,7 +184,7 @@ TestListObjects(const Aws::S3Crt::ClientConfiguration &config)
return (TEST_FAILURE);
}
- /* Expected number of matches with test_list_objects_1 prefix. */
+ // Expected number of matches with test_list_objects_1 prefix.
objects.clear();
expectedResult = 11;
if ((ret = conn.ListObjects(prefix + "1", objects)) != 0) {
@@ -178,7 +196,7 @@ TestListObjects(const Aws::S3Crt::ClientConfiguration &config)
return (TEST_FAILURE);
}
- /* List with 5 objects per AWS request. */
+ // List with 5 objects per AWS request.
objects.clear();
batchSize = 5;
expectedResult = totalObjects;
@@ -191,7 +209,7 @@ TestListObjects(const Aws::S3Crt::ClientConfiguration &config)
return (TEST_FAILURE);
}
- /* ListSingle with 8 objects per AWS request. */
+ // ListSingle with 8 objects per AWS request.
objects.clear();
expectedResult = 1;
if ((ret = conn.ListObjects(prefix, objects, batchSize, listSingle)) != 0) {
@@ -203,7 +221,7 @@ TestListObjects(const Aws::S3Crt::ClientConfiguration &config)
return (TEST_FAILURE);
}
- /* List with 8 objects per AWS request. */
+ // List with 8 objects per AWS request.
objects.clear();
batchSize = 8;
expectedResult = totalObjects;
@@ -216,7 +234,7 @@ TestListObjects(const Aws::S3Crt::ClientConfiguration &config)
return (TEST_FAILURE);
}
- /* ListSingle with 8 objects per AWS request. */
+ // ListSingle with 8 objects per AWS request.
objects.clear();
expectedResult = 1;
if ((ret = conn.ListObjects(prefix, objects, batchSize, listSingle)) != 0) {
@@ -233,10 +251,7 @@ TestListObjects(const Aws::S3Crt::ClientConfiguration &config)
return (TEST_SUCCESS);
}
-/*
- * TestGetObject --
- * Unit test to get an object from an S3 Bucket.
- */
+// Gets an object from an S3 Bucket.
int
TestGetObject(const Aws::S3Crt::ClientConfiguration &config)
{
@@ -246,24 +261,24 @@ TestGetObject(const Aws::S3Crt::ClientConfiguration &config)
const std::string objectName = "permanent_object";
const std::string path = "./" + objectName;
- /* Create a file and upload to the bucket. */
+ // Create a file and upload to the bucket.
std::ofstream File(objectName);
File << "Test payload";
File.close();
if ((ret = conn.PutObject(objectName, objectName)) != 0)
return (ret);
- /* Delete the local copy of the file. */
+ // Delete the local copy of the file.
if (std::remove(path.c_str()) != 0)
return (TEST_FAILURE);
- /* Download the file from S3 */
+ // Download the file from S3
if ((ret = conn.GetObject(objectName, path)) != 0) {
std::cerr << "TestGetObject: call to S3Connection:GetObject has failed." << std::endl;
return (ret);
}
- /* The file should now be in the current directory. */
+ // The file should now be in the current directory.
std::ifstream f(path);
if (!f.good()) {
std::cerr << "TestGetObject: target " << objectName
@@ -271,7 +286,7 @@ TestGetObject(const Aws::S3Crt::ClientConfiguration &config)
return (TEST_FAILURE);
}
- /* Clean up test artifacts. */
+ // Clean up test artifacts.
if (std::remove(path.c_str()) != 0)
return (TEST_FAILURE);
@@ -282,10 +297,7 @@ TestGetObject(const Aws::S3Crt::ClientConfiguration &config)
return (TEST_SUCCESS);
}
-/*
- * TestObjectExists --
- * Unit test to check if an object exists in an AWS bucket and size of the object is correct.
- */
+// Checks if an object exists in an AWS bucket and if the size of the object is correct.
int
TestObjectExists(const Aws::S3Crt::ClientConfiguration &config)
{
@@ -297,7 +309,7 @@ TestObjectExists(const Aws::S3Crt::ClientConfiguration &config)
const std::string objectName = "test_object";
const std::string fileName = "test_object.txt";
- /* Create a file to upload to the bucket.*/
+ // Create a file to upload to the bucket.
std::ofstream File(fileName);
std::string payload = "Test payload";
File << payload;
@@ -327,22 +339,19 @@ TestObjectExists(const Aws::S3Crt::ClientConfiguration &config)
return (TEST_SUCCESS);
}
-/*
- * TestBadBucket --
- * Unit test to check if connection to a non-existing bucket fails gracefully.
- */
+// Checks if connection to a non-existing bucket fails gracefully.
int
TestBadBucket(const Aws::S3Crt::ClientConfiguration &config)
{
int ret = TEST_FAILURE;
- /* The connection object instantitation should not succeed. */
+ // The connection object instantitation should not succeed.
try {
S3Connection conn(config, "BadBucket", TestDefaults::objPrefix);
(void)conn;
std::cerr << "TestBadBucket: Failed to generate exception for the bad bucket." << std::endl;
} catch (std::invalid_argument &e) {
- /* Make sure we get the expected exception message. */
+ // Make sure we get the expected exception message.
if (std::string(e.what()).compare("BadBucket : No such bucket.") == 0)
ret = 0;
else
@@ -354,13 +363,13 @@ TestBadBucket(const Aws::S3Crt::ClientConfiguration &config)
return (ret);
ret = TEST_FAILURE;
- /* Also check for the dynamic allocation. */
+ // Also check for the dynamic allocation.
try {
auto conn2 = new S3Connection(config, "BadBucket2", TestDefaults::objPrefix);
(void)conn2;
std::cerr << "TestBadBucket: Failed to generate exception for the bad bucket." << std::endl;
} catch (std::invalid_argument &e) {
- /* Make sure we get the expected exception message. */
+ // Make sure we get the expected exception message.
if (std::string(e.what()).compare("BadBucket2 : No such bucket.") == 0)
ret = 0;
else
@@ -375,24 +384,21 @@ TestBadBucket(const Aws::S3Crt::ClientConfiguration &config)
return (TEST_SUCCESS);
}
-/*
- * main --
- * Set up configs and call unit tests.
- */
+// Sets up configs and calls unit tests.
int
main()
{
- /* Setup the test environment. */
+ // Setup the test environment.
if (setupTestDefaults() != 0)
return (TEST_FAILURE);
- /* Set up the config to use the defaults specified. */
+ // Set up the config to use the defaults specified.
Aws::S3Crt::ClientConfiguration awsConfig;
awsConfig.region = TestDefaults::region;
awsConfig.throughputTargetGbps = TestDefaults::throughputTargetGbps;
awsConfig.partSize = TestDefaults::partSize;
- /* Set the SDK options and initialize the API. */
+ // Set the SDK options and initialize the API.
Aws::SDKOptions options;
Aws::InitAPI(options);
@@ -401,7 +407,7 @@ main()
TEST(TestListObjects, awsConfig);
TEST(TestGetObject, awsConfig);
- /* Shutdown the API at end of tests. */
+ // Shutdown the API at end of tests.
Aws::ShutdownAPI(options);
return (TEST_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/import.data b/src/third_party/wiredtiger/import.data
index ed796a51ed0..addef77d1ec 100644
--- a/src/third_party/wiredtiger/import.data
+++ b/src/third_party/wiredtiger/import.data
@@ -2,5 +2,5 @@
"vendor": "wiredtiger",
"github": "wiredtiger/wiredtiger.git",
"branch": "mongodb-master",
- "commit": "07cee370d83fd1c90f4ecf6781331db020960323"
+ "commit": "7a7d6bf9ab40cd5635ee960fac1b21edf118a007"
}