Alien-XGBoost
view release on metacpan or search on metacpan
xgboost/dmlc-core/src/io/s3_filesys.cc view on Meta::CPAN
<< " HttpReadStream: do not support Seek";
CHECK(curl_easy_setopt(ecurl, CURLOPT_URL, path_.str().c_str()) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl, CURLOPT_NOSIGNAL, 1) == CURLE_OK);
}
private:
URI path_;
};
class WriteStream : public Stream {
public:
WriteStream(const URI &path,
const std::string &aws_id,
const std::string &aws_key,
const std::string &aws_region)
: path_(path), aws_id_(aws_id),
aws_key_(aws_key), aws_region_(aws_region), closed_(false) {
const char *buz = getenv("DMLC_S3_WRITE_BUFFER_MB");
if (buz != NULL) {
max_buffer_size_ = static_cast<size_t>(atol(buz)) << 20UL;
} else {
// 64 MB
const size_t kDefaultBufferSize = 64 << 20UL;
max_buffer_size_ = kDefaultBufferSize;
}
max_error_retry_ = 3;
ecurl_ = curl_easy_init();
this->Init();
}
virtual size_t Read(void *ptr, size_t size) {
LOG(FATAL) << "S3.WriteStream cannot be used for read";
return 0;
}
virtual void Write(const void *ptr, size_t size);
// destructor
virtual ~WriteStream() {
this->Close();
}
/*! \brief Closes the write stream */
virtual void Close() {
if (!closed_) {
closed_ = true;
this->Upload(true);
this->Finish();
curl_easy_cleanup(ecurl_);
}
}
private:
// internal maximum buffer size
size_t max_buffer_size_;
// maximum time of retry when error occurs
int max_error_retry_;
// path we are reading
URI path_;
// aws access key and id
std::string aws_id_, aws_key_, aws_region_;
// easy curl handle used for the request
CURL *ecurl_;
// upload_id used by AWS
std::string upload_id_;
// write data buffer
std::string buffer_;
// etags of each part we uploaded
std::vector<std::string> etags_;
// part id of each part we uploaded
std::vector<size_t> part_ids_;
// whether the stream is closed
bool closed_;
/*!
* \brief helper function to do http post request
* \param method method to peform
* \param path the resource to post
* \param url_args additional arguments in URL
* \param url_args translated arguments to sign
* \param content_type content type of the data
* \param data data to post
* \param out_header holds output Header
* \param out_data holds output data
*/
void Run(const std::string &method,
const URI &path,
const std::string &args,
const std::string &content_type,
const std::string &data,
std::string *out_header,
std::string *out_data);
/*!
* \brief initialize the upload request
*/
void Init(void);
/*!
* \brief upload the buffer to S3, store the etag
* clear the buffer
*/
void Upload(bool force_upload_even_if_zero_bytes = false);
/*!
* \brief commit the upload and finish the session
*/
void Finish(void);
};
void WriteStream::Write(const void *ptr, size_t size) {
size_t rlen = buffer_.length();
buffer_.resize(rlen + size);
std::memcpy(BeginPtr(buffer_) + rlen, ptr, size);
if (buffer_.length() >= max_buffer_size_) {
this->Upload();
}
}
void WriteStream::Run(const std::string &method,
const URI &path,
const std::string &args,
const std::string &content_type,
const std::string &data,
std::string *out_header,
std::string *out_data) {
// initialize the curl request
std::vector<std::string> amz;
std::string md5str = ComputeMD5(data);
std::string date = GetDateString();
std::string signature = Sign(aws_key_, method.c_str(), md5str,
content_type, date, amz,
std::string("/") + path_.host + '/' +
RemoveBeginSlash(path_.name) + args);
// generate headers
std::ostringstream sauth, sdate, surl, scontent, smd5;
std::ostringstream rheader, rdata;
sauth << "Authorization: AWS " << aws_id_ << ":" << signature;
sdate << "Date: " << date;
if (path_.host.find('.', 0) == std::string::npos && aws_region_ == "us-east-1") {
// for backword compatibility, use virtual host if no period in host and no region was set.
surl << "https://" << path_.host << ".s3.amazonaws.com" << '/'
<< RemoveBeginSlash(path_.name) << args;
} else {
surl << "https://" << getEndpoint(aws_region_) << '/' << path_.host << '/'
<< RemoveBeginSlash(path_.name) << args;
}
scontent << "Content-Type: " << content_type;
// list
curl_slist *slist = NULL;
slist = curl_slist_append(slist, sdate.str().c_str());
slist = curl_slist_append(slist, scontent.str().c_str());
if (md5str.length() != 0) {
smd5 << "Content-MD5: " << md5str;
slist = curl_slist_append(slist, smd5.str().c_str());
}
slist = curl_slist_append(slist, sauth.str().c_str());
int num_retry = 0;
while (true) {
// helper for read string
ReadStringStream ss(data);
curl_easy_reset(ecurl_);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_HTTPHEADER, slist) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_URL, surl.str().c_str()) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_HEADER, 0L) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_WRITEFUNCTION, WriteSStreamCallback) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_WRITEDATA, &rdata) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_WRITEHEADER, WriteSStreamCallback) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_HEADERDATA, &rheader) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_NOSIGNAL, 1) == CURLE_OK);
if (method == "POST") {
CHECK(curl_easy_setopt(ecurl_, CURLOPT_POST, 0L) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_POSTFIELDSIZE, data.length()) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_POSTFIELDS, BeginPtr(data)) == CURLE_OK);
} else if (method == "PUT") {
CHECK(curl_easy_setopt(ecurl_, CURLOPT_PUT, 1L) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_READDATA, &ss) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_INFILESIZE_LARGE, data.length()) == CURLE_OK);
CHECK(curl_easy_setopt(ecurl_, CURLOPT_READFUNCTION, ReadStringStream::Callback) == CURLE_OK);
}
CURLcode ret = curl_easy_perform(ecurl_);
if (ret != CURLE_OK) {
LOG(INFO) << "request " << surl.str() << "failed with error "
<< curl_easy_strerror(ret) << " Progress "
<< etags_.size() << " uploaded " << " retry=" << num_retry;
num_retry += 1;
CHECK(num_retry < max_error_retry_) << " maximum retry time reached";
curl_easy_cleanup(ecurl_);
ecurl_ = curl_easy_init();
} else {
break;
}
}
curl_slist_free_all(slist);
*out_header = rheader.str();
*out_data = rdata.str();
if (FindHttpError(*out_header) ||
out_data->find("<Error>") != std::string::npos) {
LOG(FATAL) << "AWS S3 Error:\n" << *out_header << *out_data;
}
}
void WriteStream::Init(void) {
std::string rheader, rdata;
Run("POST", path_, "?uploads",
"binary/octel-stream", "", &rheader, &rdata);
XMLIter xml(rdata.c_str());
XMLIter upid;
CHECK(xml.GetNext("UploadId", &upid)) << "missing UploadId";
upload_id_ = upid.str();
}
void WriteStream::Upload(bool force_upload_even_if_zero_bytes) {
if (buffer_.length() == 0 && !force_upload_even_if_zero_bytes) return;
std::ostringstream sarg;
std::string rheader, rdata;
size_t partno = etags_.size() + 1;
sarg << "?partNumber=" << partno << "&uploadId=" << upload_id_;
Run("PUT", path_, sarg.str(),
"binary/octel-stream", buffer_, &rheader, &rdata);
const char *p = strstr(rheader.c_str(), "ETag: ");
CHECK(p != NULL) << "cannot find ETag in header";
p = strchr(p, '\"');
CHECK(p != NULL) << "cannot find ETag in header";
const char *end = strchr(p + 1, '\"');
CHECK(end != NULL) << "cannot find ETag in header";
etags_.push_back(std::string(p, end - p + 1));
part_ids_.push_back(partno);
buffer_.clear();
}
void WriteStream::Finish(void) {
std::ostringstream sarg, sdata;
std::string rheader, rdata;
sarg << "?uploadId=" << upload_id_;
sdata << "<CompleteMultipartUpload>\n";
CHECK(etags_.size() == part_ids_.size());
for (size_t i = 0; i < etags_.size(); ++i) {
sdata << " <Part>\n"
<< " <PartNumber>" << part_ids_[i] << "</PartNumber>\n"
<< " <ETag>" << etags_[i] << "</ETag>\n"
<< " </Part>\n";
}
sdata << "</CompleteMultipartUpload>\n";
Run("POST", path_, sarg.str(),
"text/xml", sdata.str(), &rheader, &rdata);
}
/*!
* \brief list the objects in the bucket with prefix specified by path.name
* \param path the path to query
* \param aws_id access id of aws
* \param aws_key access key of aws
* \paam out_list stores the output results
*/
void ListObjects(const URI &path,
const std::string aws_id,
const std::string aws_key,
const std::string aws_region,
std::vector<FileInfo> *out_list) {
CHECK(path.host.length() != 0) << "bucket name not specified in s3";
out_list->clear();
std::vector<std::string> amz;
std::string date = GetDateString();
std::string signature = Sign(aws_key, "GET", "", "", date, amz,
std::string("/") + path.host + "/");
std::ostringstream sauth, sdate, surl;
std::ostringstream result;
sauth << "Authorization: AWS " << aws_id << ":" << signature;
sdate << "Date: " << date;
if (path.host.find('.', 0) == std::string::npos && aws_region == "us-east-1") {
// for backword compatibility, use virtual host if no period in host and no region was set.
surl << "https://" << path.host << ".s3.amazonaws.com"
<< "/?delimiter=/&prefix=" << RemoveBeginSlash(path.name);
} else {
surl << "https://" << getEndpoint(aws_region) << "/" << path.host
<< "/?delimiter=/&prefix=" << RemoveBeginSlash(path.name);
}
// make request
CURL *curl = curl_easy_init();
curl_slist *slist = NULL;
slist = curl_slist_append(slist, sdate.str().c_str());
slist = curl_slist_append(slist, sauth.str().c_str());
CHECK(curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist) == CURLE_OK);
CHECK(curl_easy_setopt(curl, CURLOPT_URL, surl.str().c_str()) == CURLE_OK);
CHECK(curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L) == CURLE_OK);
CHECK(curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteSStreamCallback) == CURLE_OK);
CHECK(curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result) == CURLE_OK);
CHECK(curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1) == CURLE_OK);
CHECK(curl_easy_perform(curl) == CURLE_OK);
curl_slist_free_all(slist);
curl_easy_cleanup(curl);
// parse xml
std::string ret = result.str();
( run in 1.507 second using v1.01-cache-2.11-cpan-b16cb0d3907 )