diff options
author | Luke Chen <luke.chen@mongodb.com> | 2022-02-22 13:40:33 +1100 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-02-22 03:06:00 +0000 |
commit | 10f64703a649ce5f2b927585966fc30bc90dd70f (patch) | |
tree | 97c0bb54eaf00f6d613095da647eff0e288437b3 | |
parent | 914d57bf82a343df345ebb6b0700e368a82d80e8 (diff) | |
download | mongo-10f64703a649ce5f2b927585966fc30bc90dd70f.tar.gz |
Import wiredtiger: 11425af9b5e47adb7a79ae94b392f50874220965 from branch mongodb-5.3
ref: dd462d128d..11425af9b5
for: 5.3.0-rc1
WT-8785 Log errors in the S3 extension
4 files changed, 139 insertions, 71 deletions
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 f5aadbdd676..b8ba9ec1212 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 @@ -2,14 +2,9 @@ #include "s3_log_system.h" #include <cstdarg> -S3LogSystem::S3LogSystem(WT_EXTENSION_API *wtApi, uint32_t wtVerbosityLevel) - : _wtApi(wtApi), _wtVerbosityLevel(wtVerbosityLevel) +S3LogSystem::S3LogSystem(WT_EXTENSION_API *wtApi, uint32_t wtVerbosityLevel) : _wtApi(wtApi) { - // 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; + SetWtVerbosityLevel(wtVerbosityLevel); } void @@ -52,10 +47,39 @@ S3LogSystem::LogAwsMessage(const char *tag, const std::string &message) const } void -S3LogSystem::LogVerboseMessage(int32_t verbosityLevel, const std::string &message) +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) + _wtApi->err_printf(_wtApi, NULL, "%s", message.c_str()); + else + _wtApi->msg_printf(_wtApi, NULL, "%s", message.c_str()); + } +} + +void +S3LogSystem::LogVerboseErrorMessage(const std::string &message) const +{ + LogVerboseMessage(WT_VERBOSE_ERROR, message); +} + +void +S3LogSystem::LogVerboseDebugMessage(const std::string &message) const +{ + LogVerboseMessage(WT_VERBOSE_DEBUG, message); +} + +void +S3LogSystem::SetWtVerbosityLevel(int32_t wtVerbosityLevel) { - if (verbosityLevel <= _wtVerbosityLevel) - _wtApi->err_printf(_wtApi, NULL, "%s", message.c_str()); + _wtVerbosityLevel = wtVerbosityLevel; + /* 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 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 bf527d6fdff..3327ae32443 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 @@ -26,11 +26,14 @@ 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 LogVerboseErrorMessage(const std::string &message) const; + void LogVerboseDebugMessage(const std::string &message) const; + void SetWtVerbosityLevel(int32_t wtVerbosityLevel); void Flush() override; private: void LogAwsMessage(const char *tag, const std::string &message) const; - void LogVerboseMessage(int32_t verbosityLevel, const std::string &message); + void LogVerboseMessage(int32_t verbosityLevel, const std::string &message) const; std::atomic<Aws::Utils::Logging::LogLevel> _awsLogLevel; WT_EXTENSION_API *_wtApi; int32_t _wtVerbosityLevel; 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 c579ea53394..3d1b8c200c0 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 @@ -62,6 +62,7 @@ struct S3_STATISTICS { struct S3_STORAGE { 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 */ @@ -85,7 +86,6 @@ struct S3_FILE_SYSTEM { */ WT_FILE_SYSTEM *wtFileSystem; S3Connection *connection; - S3LogSystem *log; std::string cacheDir; /* Directory for cached objects */ std::string homeDir; /* Owned by the connection */ }; @@ -108,7 +108,8 @@ const uint64_t partSize = 8 * 1024 * 1024; /* 8 MB. */ /* Setting SDK options. */ Aws::SDKOptions options; -static int S3GetDirectory(const std::string &, const std::string &, bool, std::string &); +static int S3GetDirectory( + const S3_STORAGE &, 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 *); @@ -125,11 +126,11 @@ 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( - S3_STORAGE *, char ***, const std::vector<std::string> &, const uint32_t); + const S3_STORAGE &, 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_STATISTICS &); +static void S3ShowStatistics(const S3_STORAGE &); static int S3FileClose(WT_FILE_HANDLE *, WT_SESSION *); static int S3FileSize(WT_FILE_HANDLE *, WT_SESSION *, wt_off_t *); @@ -164,6 +165,7 @@ S3Exist(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name, bool { size_t objectSize; S3_FILE_SYSTEM *fs = (S3_FILE_SYSTEM *)fileSystem; + S3_STORAGE *s3 = FS2S3(fileSystem); int ret = 0; /* Check if file exists in the cache. */ @@ -172,9 +174,10 @@ S3Exist(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name, bool return (ret); /* It's not in the cache, try the S3 bucket. */ - FS2S3(fileSystem)->statistics.objectExistsCount++; + s3->statistics.objectExistsCount++; if ((ret = fs->connection->ObjectExists(name, *exist, objectSize)) != 0) - std::cerr << "S3Exist: ObjectExists request to S3 failed." << std::endl; + s3->log->LogVerboseErrorMessage("S3Exist: ObjectExists request to S3 failed."); + return (ret); } @@ -205,7 +208,8 @@ LocalFileExists(const std::string &path) * Return a copy of a directory name after verifying that it is a directory. */ static int -S3GetDirectory(const std::string &home, const std::string &name, bool create, std::string ©) +S3GetDirectory(const S3_STORAGE &s3, const std::string &home, const std::string &name, bool create, + std::string ©) { copy = ""; @@ -224,11 +228,13 @@ S3GetDirectory(const std::string &home, const std::string &name, bool create, st mkdir(dirName.c_str(), 0777); ret = stat(dirName.c_str(), &sb); } - - if (ret != 0) + if (ret != 0) { + s3.log->LogVerboseErrorMessage("S3GetDirectory: stat system call failed."); ret = errno; - else if ((sb.st_mode & S_IFMT) != S_IFDIR) + } else if ((sb.st_mode & S_IFMT) != S_IFDIR) { + s3.log->LogVerboseErrorMessage("S3GetDirectory: invalid directory name."); ret = EINVAL; + } copy = dirName; return (ret); @@ -255,7 +261,8 @@ S3FileClose(WT_FILE_HANDLE *fileHandle, WT_SESSION *session) } if (wtFileHandle != NULL) { s3->statistics.fhOps++; - ret = wtFileHandle->close(wtFileHandle, session); + if ((ret = wtFileHandle->close(wtFileHandle, session)) != 0) + s3->log->LogVerboseErrorMessage("S3FileClose: close file handle failed."); } free(s3FileHandle->iface.name); @@ -282,7 +289,7 @@ S3Open(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name, /* We only support opening the file in read only mode. */ if ((flags & WT_FS_OPEN_READONLY) == 0 || (flags & WT_FS_OPEN_CREATE) != 0) { - std::cerr << "ss_open_object: readonly access required: " << name << std::endl; + s3->log->LogVerboseErrorMessage("S3Open: read-only access required."); return (EINVAL); } @@ -291,19 +298,21 @@ S3Open(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name, * the future. */ if (fileType != WT_FS_OPEN_FILE_TYPE_DATA && fileType != WT_FS_OPEN_FILE_TYPE_REGULAR) { - std::cerr << name << ": open: only data file and regular types supported" << std::endl; + s3->log->LogVerboseErrorMessage("S3Open: only data file and regular types supported."); return (EINVAL); } - if ((s3FileHandle = (S3_FILE_HANDLE *)calloc(1, sizeof(S3_FILE_HANDLE))) == NULL) + if ((s3FileHandle = (S3_FILE_HANDLE *)calloc(1, sizeof(S3_FILE_HANDLE))) == NULL) { + s3->log->LogVerboseErrorMessage("S3Open: unable to allocate memory for file handle."); return (ENOMEM); + } /* 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) { - std::cerr << "ss_open_object: GetObject request to S3 failed." << std::endl; + s3->log->LogVerboseErrorMessage("S3Open: GetObject request to S3 failed."); return (ret); } } @@ -312,7 +321,7 @@ S3Open(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name, ret = wtFileSystem->fs_open_file( wtFileSystem, session, cachePath.c_str(), fileType, flags, &wtFileHandle); if (ret != 0) { - std::cerr << "ss_open_object: fs_open_file failed." << name << std::endl; + s3->log->LogVerboseErrorMessage("S3Open: fs_open_file failed."); return (ret); } @@ -338,7 +347,7 @@ S3Open(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *name, fileHandle->name = strdup(name); if (fileHandle->name == NULL) { - std::cout << "ss_open_object: unable to allocate memory for object name" << std::endl; + s3->log->LogVerboseErrorMessage("S3Open: unable to allocate memory for object name."); return (ENOMEM); } @@ -389,7 +398,7 @@ S3FileRead(WT_FILE_HANDLE *fileHandle, WT_SESSION *session, wt_off_t offset, siz int ret; s3->statistics.fhReadOps++; if ((ret = wtFileHandle->fh_read(wtFileHandle, session, offset, len, buf)) != 0) - std::cerr << "S3FileRead: fh_read failed." << std::endl; + s3->log->LogVerboseErrorMessage("S3FileRead: fh_read failed."); return (ret); } @@ -428,7 +437,7 @@ S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, con /* We need to have a bucket to setup the file system. */ if (bucketName == NULL || strlen(bucketName) == 0) { - std::cerr << "Error: Bucket not specified"; + s3->log->LogVerboseErrorMessage("S3CustomizeFileSystem: bucket not specified."); return (EINVAL); } @@ -443,7 +452,8 @@ S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, con s3->wtApi, session, config, "prefix", &objPrefixConf)) == 0) objPrefix = std::string(objPrefixConf.str, objPrefixConf.len); else if (ret != WT_NOTFOUND) { - std::cerr << "Error: customize_file_system: config parsing for object prefix"; + s3->log->LogVerboseErrorMessage( + "S3CustomizeFileSystem: error parsing config for object prefix."); return (ret); } @@ -462,10 +472,11 @@ S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, con 0) awsConfig.region = std::string(regionConf.str, regionConf.len); else if (ret != WT_NOTFOUND) { - std::cerr << "Error: customize_file_system: config parsing for AWS region"; + s3->log->LogVerboseErrorMessage( + "S3CustomizeFileSystem: error parsing config for AWS region."); return (ret); } else { - std::cerr << "Error: Region not specified" << std::endl; + s3->log->LogVerboseErrorMessage("S3CustomizeFileSystem: AWS region not specified."); return (EINVAL); } /* @@ -481,8 +492,11 @@ S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, con else if (ret == WT_NOTFOUND) { cacheStr = "cache-" + std::string(bucketName); ret = 0; - } else + } else { + s3->log->LogVerboseErrorMessage( + "wiredtiger_extension_init: error parsing config for cache directory."); return (ret); + } /* Fetch the native WT file system. */ if ((ret = s3->wtApi->file_system_get(s3->wtApi, session, &wtFileSystem)) != 0) @@ -490,12 +504,15 @@ S3CustomizeFileSystem(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session, con /* Get a copy of the home and cache directory. */ const std::string homeDir = session->connection->get_home(session->connection); - if ((ret = S3GetDirectory(homeDir, cacheStr, true, cacheDir)) != 0) + 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) - return (errno); + if ((fs = (S3_FILE_SYSTEM *)calloc(1, sizeof(S3_FILE_SYSTEM))) == NULL) { + s3->log->LogVerboseErrorMessage( + "S3CustomizeFileSystem: unable to allocate memory for file system."); + return (ENOMEM); + } fs->storage = s3; fs->wtFileSystem = wtFileSystem; fs->homeDir = homeDir; @@ -570,12 +587,12 @@ S3ObjectList(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char *direct int ret; s3->statistics.listObjectsCount++; if ((ret = fs->connection->ListObjects(completePrefix, objects)) != 0) { - std::cerr << "S3ObjectList: ListObjects request to S3 failed." << std::endl; + s3->log->LogVerboseErrorMessage("S3ObjectList: ListObjects request to S3 failed."); return (ret); } *count = objects.size(); - S3ObjectListAdd(s3, objectList, objects, *count); + S3ObjectListAdd(*s3, objectList, objects, *count); return (ret); } @@ -606,13 +623,13 @@ S3ObjectListSingle(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, const char * int ret; s3->statistics.listObjectsCount++; if ((ret = fs->connection->ListObjects(completePrefix, objects, 1, true)) != 0) { - std::cerr << "S3ObjectListSingle: ListObjects request to S3 failed." << std::endl; + s3->log->LogVerboseErrorMessage("S3ObjectListSingle: ListObjects request to S3 failed."); return (ret); } *count = objects.size(); - S3ObjectListAdd(s3, objectList, objects, *count); + S3ObjectListAdd(*s3, objectList, objects, *count); return (ret); } @@ -641,12 +658,22 @@ S3ObjectListFree(WT_FILE_SYSTEM *fileSystem, WT_SESSION *session, char **objectL * Add objects retrieved from S3 bucket into the object list, and allocate the memory needed. */ static int -S3ObjectListAdd( - S3_STORAGE *s3, char ***objectList, const std::vector<std::string> &objects, const uint32_t count) +S3ObjectListAdd(const S3_STORAGE &s3, char ***objectList, const std::vector<std::string> &objects, + const uint32_t count) { - char **entries = (char **)malloc(sizeof(char *) * count); + char **entries; + if ((entries = (char **)malloc(sizeof(char *) * count)) == NULL) { + s3.log->LogVerboseErrorMessage( + "S3ObjectListAdd: unable to allocate memory for object list."); + return (ENOMEM); + } + for (int i = 0; i < count; i++) { - entries[i] = strdup(objects[i].c_str()); + if ((entries[i] = strdup(objects[i].c_str())) == NULL) { + s3.log->LogVerboseErrorMessage( + "S3ObjectListAdd: unable to allocate memory for object string."); + return (ENOMEM); + } } *objectList = entries; @@ -663,11 +690,10 @@ S3AddReference(WT_STORAGE_SOURCE *storageSource) { S3_STORAGE *s3 = (S3_STORAGE *)storageSource; - /* - * Missing reference or overflow? - */ - if (s3->referenceCount == 0 || s3->referenceCount + 1 == 0) + if (s3->referenceCount == 0 || s3->referenceCount + 1 == 0) { + s3->log->LogVerboseErrorMessage("S3AddReference: missing reference or overflow."); return (EINVAL); + } ++s3->referenceCount; return (0); @@ -705,7 +731,7 @@ S3Terminate(WT_STORAGE_SOURCE *storageSource, WT_SESSION *session) } /* Log collected statistics on termination. */ - S3ShowStatistics(s3->statistics); + S3ShowStatistics(*s3); Aws::Utils::Logging::ShutdownAWSLogging(); Aws::ShutdownAPI(options); @@ -722,12 +748,14 @@ 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; int ret; FS2S3(fileSystem)->statistics.putObjectCount++; - if ((ret = fs->connection->PutObject(object, source)) != 0) - std::cerr << "S3Flush: PutObject request to S3 failed." << std::endl; + if (ret = (fs->connection->PutObject(object, source)) != 0) + s3->log->LogVerboseErrorMessage("S3Flush: PutObject request to S3 failed."); + return (ret); } @@ -758,15 +786,21 @@ S3FlushFinish(WT_STORAGE_SOURCE *storage, WT_SESSION *session, WT_FILE_SYSTEM *f * Log collected statistics. */ static void -S3ShowStatistics(const S3_STATISTICS &statistics) +S3ShowStatistics(const S3_STORAGE &s3) { - std::cout << "S3 list objects count: " << statistics.listObjectsCount << std::endl; - std::cout << "S3 put object count: " << statistics.putObjectCount << std::endl; - std::cout << "S3 get object count: " << statistics.getObjectCount << std::endl; - std::cout << "S3 object exists count: " << statistics.objectExistsCount << std::endl; - - std::cout << "Non read/write file handle operations: " << statistics.fhOps << std::endl; - std::cout << "File handle read operations: " << statistics.fhReadOps << std::endl; + s3.log->LogVerboseDebugMessage( + "S3 list objects count: " + std::to_string(s3.statistics.listObjectsCount)); + s3.log->LogVerboseDebugMessage( + "S3 put object count: " + std::to_string(s3.statistics.putObjectCount)); + s3.log->LogVerboseDebugMessage( + "S3 get object count: " + std::to_string(s3.statistics.getObjectCount)); + s3.log->LogVerboseDebugMessage( + "S3 object exists count: " + std::to_string(s3.statistics.objectExistsCount)); + + s3.log->LogVerboseDebugMessage( + "Non read/write file handle operations: " + std::to_string(s3.statistics.fhOps)); + s3.log->LogVerboseDebugMessage( + "File handle read operations: " + std::to_string(s3.statistics.fhReadOps)); } /* @@ -780,28 +814,35 @@ wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config) S3_FILE_SYSTEM *fs; WT_CONFIG_ITEM v; + /* No error handling for now. */ s3 = new S3_STORAGE; s3->wtApi = connection->get_extension_api(connection); int ret = s3->wtApi->config_get(s3->wtApi, NULL, config, "verbose", &v); - // If a verbose level is not found, it will set the level to -3 (Error). - if (ret == 0 && v.val >= -3 && v.val <= 1) + /* + * 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); + + if (ret == 0 && v.val >= WT_VERBOSE_ERROR && v.val <= WT_VERBOSE_DEBUG) { s3->verbose = v.val; - else if (ret == WT_NOTFOUND) - s3->verbose = -3; - else { - free(s3); + s3->log->SetWtVerbosityLevel(s3->verbose); + } else if (ret != WT_NOTFOUND) { + s3->log->LogVerboseErrorMessage( + "wiredtiger_extension_init: error parsing config for verbose level."); + delete (s3); return (ret != 0 ? ret : EINVAL); } /* Set up statistics. */ s3->statistics = {0}; - /* Create a logger for this storage source, and then initialize the AWS SDK. */ - Aws::Utils::Logging::InitializeAWSLogging( - Aws::MakeShared<S3LogSystem>("storage", s3->wtApi, s3->verbose)); + /* Initialize the AWS SDK. */ + Aws::Utils::Logging::InitializeAWSLogging(s3->log); Aws::InitAPI(options); /* @@ -822,7 +863,7 @@ wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config) /* Load the storage */ if ((ret = connection->add_storage_source(connection, "s3_store", &s3->storageSource, NULL)) != 0) - free(s3); + delete (s3); return (ret); } diff --git a/src/third_party/wiredtiger/import.data b/src/third_party/wiredtiger/import.data index 958c0c71477..f07a6bde910 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-5.3", - "commit": "dd462d128df33f64b3448338e5d34bd5d6c86bfc" + "commit": "11425af9b5e47adb7a79ae94b392f50874220965" } |