2016-02-09 23:12:00 +00:00
|
|
|
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
2017-07-15 23:03:42 +00:00
|
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
|
|
// (found in the LICENSE.Apache file in the root directory).
|
2013-10-16 21:59:46 +00:00
|
|
|
//
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2013-10-05 05:32:05 +00:00
|
|
|
#pragma once
|
2012-06-08 08:11:14 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <iostream>
|
2015-07-01 23:13:49 +00:00
|
|
|
#include "port/sys_time.h"
|
2013-08-23 15:38:13 +00:00
|
|
|
#include "rocksdb/env.h"
|
|
|
|
#include "rocksdb/status.h"
|
2012-06-08 08:11:14 +00:00
|
|
|
|
|
|
|
#ifdef USE_HDFS
|
2014-05-20 21:22:12 +00:00
|
|
|
#include <hdfs.h>
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2013-10-04 04:49:15 +00:00
|
|
|
namespace rocksdb {
|
2012-06-08 08:11:14 +00:00
|
|
|
|
|
|
|
// Thrown during execution when there is an issue with the supplied
|
|
|
|
// arguments.
|
|
|
|
class HdfsUsageException : public std::exception { };
|
|
|
|
|
|
|
|
// A simple exception that indicates something went wrong that is not
|
|
|
|
// recoverable. The intention is for the message to be printed (with
|
|
|
|
// nothing else) and the process terminate.
|
|
|
|
class HdfsFatalException : public std::exception {
|
|
|
|
public:
|
|
|
|
explicit HdfsFatalException(const std::string& s) : what_(s) { }
|
|
|
|
virtual ~HdfsFatalException() throw() { }
|
|
|
|
virtual const char* what() const throw() {
|
|
|
|
return what_.c_str();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
const std::string what_;
|
|
|
|
};
|
|
|
|
|
|
|
|
//
|
2013-10-05 05:32:05 +00:00
|
|
|
// The HDFS environment for rocksdb. This class overrides all the
|
2012-06-08 08:11:14 +00:00
|
|
|
// file/dir access methods and delegates the thread-mgmt methods to the
|
|
|
|
// default posix environment.
|
|
|
|
//
|
|
|
|
class HdfsEnv : public Env {
|
|
|
|
|
|
|
|
public:
|
2014-02-26 01:47:37 +00:00
|
|
|
explicit HdfsEnv(const std::string& fsname) : fsname_(fsname) {
|
2012-06-08 08:11:14 +00:00
|
|
|
posixEnv = Env::Default();
|
|
|
|
fileSys_ = connectToPath(fsname_);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~HdfsEnv() {
|
|
|
|
fprintf(stderr, "Destroying HdfsEnv::Default()\n");
|
|
|
|
hdfsDisconnect(fileSys_);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Status NewSequentialFile(const std::string& fname,
|
2014-05-14 19:14:18 +00:00
|
|
|
std::unique_ptr<SequentialFile>* result,
|
|
|
|
const EnvOptions& options);
|
2012-06-08 08:11:14 +00:00
|
|
|
|
|
|
|
virtual Status NewRandomAccessFile(const std::string& fname,
|
2014-05-14 19:14:18 +00:00
|
|
|
std::unique_ptr<RandomAccessFile>* result,
|
|
|
|
const EnvOptions& options);
|
2012-06-08 08:11:14 +00:00
|
|
|
|
|
|
|
virtual Status NewWritableFile(const std::string& fname,
|
2014-05-14 19:14:18 +00:00
|
|
|
std::unique_ptr<WritableFile>* result,
|
|
|
|
const EnvOptions& options);
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2014-01-27 19:02:21 +00:00
|
|
|
virtual Status NewDirectory(const std::string& name,
|
2014-05-14 19:14:18 +00:00
|
|
|
std::unique_ptr<Directory>* result);
|
2014-01-27 19:02:21 +00:00
|
|
|
|
2015-07-21 00:20:40 +00:00
|
|
|
virtual Status FileExists(const std::string& fname);
|
2012-06-08 08:11:14 +00:00
|
|
|
|
|
|
|
virtual Status GetChildren(const std::string& path,
|
|
|
|
std::vector<std::string>* result);
|
|
|
|
|
|
|
|
virtual Status DeleteFile(const std::string& fname);
|
|
|
|
|
|
|
|
virtual Status CreateDir(const std::string& name);
|
|
|
|
|
2012-11-26 21:56:45 +00:00
|
|
|
virtual Status CreateDirIfMissing(const std::string& name);
|
|
|
|
|
2012-06-08 08:11:14 +00:00
|
|
|
virtual Status DeleteDir(const std::string& name);
|
|
|
|
|
|
|
|
virtual Status GetFileSize(const std::string& fname, uint64_t* size);
|
|
|
|
|
2012-11-26 21:56:45 +00:00
|
|
|
virtual Status GetFileModificationTime(const std::string& fname,
|
|
|
|
uint64_t* file_mtime);
|
|
|
|
|
2012-06-08 08:11:14 +00:00
|
|
|
virtual Status RenameFile(const std::string& src, const std::string& target);
|
|
|
|
|
2015-12-02 13:46:48 +00:00
|
|
|
virtual Status LinkFile(const std::string& src, const std::string& target) {
|
|
|
|
return Status::NotSupported(); // not supported
|
|
|
|
}
|
2014-11-14 19:38:26 +00:00
|
|
|
|
2012-06-08 08:11:14 +00:00
|
|
|
virtual Status LockFile(const std::string& fname, FileLock** lock);
|
|
|
|
|
|
|
|
virtual Status UnlockFile(FileLock* lock);
|
|
|
|
|
2014-05-14 19:14:18 +00:00
|
|
|
virtual Status NewLogger(const std::string& fname,
|
|
|
|
std::shared_ptr<Logger>* result);
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2013-09-12 07:53:30 +00:00
|
|
|
virtual void Schedule(void (*function)(void* arg), void* arg,
|
2015-12-30 03:51:49 +00:00
|
|
|
Priority pri = LOW, void* tag = nullptr, void (*unschedFunction)(void* arg) = 0) {
|
2015-12-30 18:12:44 +00:00
|
|
|
posixEnv->Schedule(function, arg, pri, tag, unschedFunction);
|
2015-03-17 01:49:14 +00:00
|
|
|
}
|
|
|
|
|
2015-03-17 04:07:54 +00:00
|
|
|
virtual int UnSchedule(void* tag, Priority pri) {
|
2016-09-14 17:17:34 +00:00
|
|
|
return posixEnv->UnSchedule(tag, pri);
|
2012-06-08 08:11:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void StartThread(void (*function)(void* arg), void* arg) {
|
|
|
|
posixEnv->StartThread(function, arg);
|
|
|
|
}
|
|
|
|
|
2014-02-26 01:47:37 +00:00
|
|
|
virtual void WaitForJoin() { posixEnv->WaitForJoin(); }
|
|
|
|
|
2014-03-10 23:14:48 +00:00
|
|
|
virtual unsigned int GetThreadPoolQueueLen(Priority pri = LOW) const
|
|
|
|
override {
|
|
|
|
return posixEnv->GetThreadPoolQueueLen(pri);
|
|
|
|
}
|
|
|
|
|
2012-06-08 08:11:14 +00:00
|
|
|
virtual Status GetTestDirectory(std::string* path) {
|
|
|
|
return posixEnv->GetTestDirectory(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual uint64_t NowMicros() {
|
|
|
|
return posixEnv->NowMicros();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void SleepForMicroseconds(int micros) {
|
|
|
|
posixEnv->SleepForMicroseconds(micros);
|
|
|
|
}
|
|
|
|
|
2012-09-12 16:54:22 +00:00
|
|
|
virtual Status GetHostName(char* name, uint64_t len) {
|
2012-08-14 22:20:36 +00:00
|
|
|
return posixEnv->GetHostName(name, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Status GetCurrentTime(int64_t* unix_time) {
|
2012-08-29 22:21:56 +00:00
|
|
|
return posixEnv->GetCurrentTime(unix_time);
|
2012-08-14 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual Status GetAbsolutePath(const std::string& db_path,
|
|
|
|
std::string* output_path) {
|
|
|
|
return posixEnv->GetAbsolutePath(db_path, output_path);
|
|
|
|
}
|
|
|
|
|
2013-09-12 07:53:30 +00:00
|
|
|
virtual void SetBackgroundThreads(int number, Priority pri = LOW) {
|
|
|
|
posixEnv->SetBackgroundThreads(number, pri);
|
2012-09-19 22:21:09 +00:00
|
|
|
}
|
2012-08-14 22:20:36 +00:00
|
|
|
|
2017-05-23 18:04:25 +00:00
|
|
|
virtual int GetBackgroundThreads(Priority pri = LOW) {
|
|
|
|
return posixEnv->GetBackgroundThreads(pri);
|
|
|
|
}
|
|
|
|
|
2014-11-03 22:11:33 +00:00
|
|
|
virtual void IncBackgroundThreadsIfNeeded(int number, Priority pri) override {
|
|
|
|
posixEnv->IncBackgroundThreadsIfNeeded(number, pri);
|
|
|
|
}
|
|
|
|
|
2012-10-19 21:00:53 +00:00
|
|
|
virtual std::string TimeToString(uint64_t number) {
|
|
|
|
return posixEnv->TimeToString(number);
|
|
|
|
}
|
|
|
|
|
2012-06-08 08:11:14 +00:00
|
|
|
static uint64_t gettid() {
|
|
|
|
assert(sizeof(pthread_t) <= sizeof(uint64_t));
|
|
|
|
return (uint64_t)pthread_self();
|
|
|
|
}
|
|
|
|
|
2015-06-11 21:18:02 +00:00
|
|
|
virtual uint64_t GetThreadID() const override {
|
|
|
|
return HdfsEnv::gettid();
|
|
|
|
}
|
|
|
|
|
2012-06-08 08:11:14 +00:00
|
|
|
private:
|
|
|
|
std::string fsname_; // string of the form "hdfs://hostname:port/"
|
|
|
|
hdfsFS fileSys_; // a single FileSystem object for all files
|
|
|
|
Env* posixEnv; // This object is derived from Env, but not from
|
|
|
|
// posixEnv. We have posixnv as an encapsulated
|
|
|
|
// object here so that we can use posix timers,
|
|
|
|
// posix threads, etc.
|
|
|
|
|
2014-05-14 19:14:18 +00:00
|
|
|
static const std::string kProto;
|
|
|
|
static const std::string pathsep;
|
|
|
|
|
2012-06-08 08:11:14 +00:00
|
|
|
/**
|
2013-01-07 18:11:18 +00:00
|
|
|
* If the URI is specified of the form hdfs://server:port/path,
|
2012-06-08 08:11:14 +00:00
|
|
|
* then connect to the specified cluster
|
|
|
|
* else connect to default.
|
|
|
|
*/
|
|
|
|
hdfsFS connectToPath(const std::string& uri) {
|
|
|
|
if (uri.empty()) {
|
2014-02-26 01:47:37 +00:00
|
|
|
return nullptr;
|
2012-06-08 08:11:14 +00:00
|
|
|
}
|
|
|
|
if (uri.find(kProto) != 0) {
|
|
|
|
// uri doesn't start with hdfs:// -> use default:0, which is special
|
|
|
|
// to libhdfs.
|
|
|
|
return hdfsConnectNewInstance("default", 0);
|
|
|
|
}
|
|
|
|
const std::string hostport = uri.substr(kProto.length());
|
|
|
|
|
|
|
|
std::vector <std::string> parts;
|
|
|
|
split(hostport, ':', parts);
|
|
|
|
if (parts.size() != 2) {
|
|
|
|
throw HdfsFatalException("Bad uri for hdfs " + uri);
|
|
|
|
}
|
|
|
|
// parts[0] = hosts, parts[1] = port/xxx/yyy
|
|
|
|
std::string host(parts[0]);
|
|
|
|
std::string remaining(parts[1]);
|
|
|
|
|
|
|
|
int rem = remaining.find(pathsep);
|
|
|
|
std::string portStr = (rem == 0 ? remaining :
|
|
|
|
remaining.substr(0, rem));
|
2013-01-07 18:11:18 +00:00
|
|
|
|
2012-06-08 08:11:14 +00:00
|
|
|
tPort port;
|
|
|
|
port = atoi(portStr.c_str());
|
|
|
|
if (port == 0) {
|
|
|
|
throw HdfsFatalException("Bad host-port for hdfs " + uri);
|
|
|
|
}
|
|
|
|
hdfsFS fs = hdfsConnectNewInstance(host.c_str(), port);
|
|
|
|
return fs;
|
|
|
|
}
|
|
|
|
|
2013-01-07 18:11:18 +00:00
|
|
|
void split(const std::string &s, char delim,
|
2012-06-08 08:11:14 +00:00
|
|
|
std::vector<std::string> &elems) {
|
|
|
|
elems.clear();
|
|
|
|
size_t prev = 0;
|
|
|
|
size_t pos = s.find(delim);
|
|
|
|
while (pos != std::string::npos) {
|
|
|
|
elems.push_back(s.substr(prev, pos));
|
|
|
|
prev = pos + 1;
|
|
|
|
pos = s.find(delim, prev);
|
|
|
|
}
|
|
|
|
elems.push_back(s.substr(prev, s.size()));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-10-04 04:49:15 +00:00
|
|
|
} // namespace rocksdb
|
2012-06-08 08:11:14 +00:00
|
|
|
|
|
|
|
#else // USE_HDFS
|
|
|
|
|
|
|
|
|
2013-10-04 04:49:15 +00:00
|
|
|
namespace rocksdb {
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2012-08-29 19:29:43 +00:00
|
|
|
static const Status notsup;
|
|
|
|
|
2012-06-08 08:11:14 +00:00
|
|
|
class HdfsEnv : public Env {
|
|
|
|
|
|
|
|
public:
|
2017-07-21 21:50:24 +00:00
|
|
|
explicit HdfsEnv(const std::string& /*fsname*/) {
|
2013-10-05 05:32:05 +00:00
|
|
|
fprintf(stderr, "You have not build rocksdb with HDFS support\n");
|
2012-06-08 08:11:14 +00:00
|
|
|
fprintf(stderr, "Please see hdfs/README for details\n");
|
2014-12-05 21:30:57 +00:00
|
|
|
abort();
|
2012-06-08 08:11:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~HdfsEnv() {
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Status NewSequentialFile(const std::string& fname,
|
2013-03-15 00:00:04 +00:00
|
|
|
unique_ptr<SequentialFile>* result,
|
2015-02-26 19:28:41 +00:00
|
|
|
const EnvOptions& options) override;
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status NewRandomAccessFile(const std::string& /*fname*/,
|
|
|
|
unique_ptr<RandomAccessFile>* /*result*/,
|
|
|
|
const EnvOptions& /*options*/) override {
|
2013-01-20 10:07:13 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status NewWritableFile(const std::string& /*fname*/,
|
|
|
|
unique_ptr<WritableFile>* /*result*/,
|
|
|
|
const EnvOptions& /*options*/) override {
|
2013-01-20 10:07:13 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status NewDirectory(const std::string& /*name*/,
|
|
|
|
unique_ptr<Directory>* /*result*/) override {
|
2014-01-27 19:02:21 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status FileExists(const std::string& /*fname*/) override {
|
2015-07-21 00:20:40 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status GetChildren(const std::string& /*path*/,
|
|
|
|
std::vector<std::string>* /*result*/) override {
|
2015-02-26 19:28:41 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status DeleteFile(const std::string& /*fname*/) override {
|
2015-02-26 19:28:41 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status CreateDir(const std::string& /*name*/) override {
|
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status CreateDirIfMissing(const std::string& /*name*/) override {
|
2015-02-26 19:28:41 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-11-26 21:56:45 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status DeleteDir(const std::string& /*name*/) override {
|
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status GetFileSize(const std::string& /*fname*/,
|
|
|
|
uint64_t* /*size*/) override {
|
2015-02-26 19:28:41 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status GetFileModificationTime(const std::string& /*fname*/,
|
|
|
|
uint64_t* /*time*/) override {
|
2012-11-26 21:56:45 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status RenameFile(const std::string& /*src*/,
|
|
|
|
const std::string& /*target*/) override {
|
2015-02-26 19:28:41 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status LinkFile(const std::string& /*src*/,
|
|
|
|
const std::string& /*target*/) override {
|
2014-11-14 19:38:26 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status LockFile(const std::string& /*fname*/,
|
|
|
|
FileLock** /*lock*/) override {
|
2015-02-26 19:28:41 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status UnlockFile(FileLock* /*lock*/) override { return notsup; }
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status NewLogger(const std::string& /*fname*/,
|
|
|
|
shared_ptr<Logger>* /*result*/) override {
|
2015-02-26 19:28:41 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual void Schedule(void (*/*function*/)(void* arg), void* /*arg*/,
|
|
|
|
Priority /*pri*/ = LOW, void* /*tag*/ = nullptr,
|
|
|
|
void (*/*unschedFunction*/)(void* arg) = 0) override {}
|
2015-03-17 01:49:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual int UnSchedule(void* /*tag*/, Priority /*pri*/) override { return 0; }
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual void StartThread(void (*/*function*/)(void* arg),
|
|
|
|
void* /*arg*/) override {}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2015-02-26 19:28:41 +00:00
|
|
|
virtual void WaitForJoin() override {}
|
2014-02-26 01:47:37 +00:00
|
|
|
|
2015-02-26 19:28:41 +00:00
|
|
|
virtual unsigned int GetThreadPoolQueueLen(
|
2017-07-21 21:50:24 +00:00
|
|
|
Priority /*pri*/ = LOW) const override {
|
2014-03-10 23:14:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status GetTestDirectory(std::string* /*path*/) override {
|
|
|
|
return notsup;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2015-02-26 19:28:41 +00:00
|
|
|
virtual uint64_t NowMicros() override { return 0; }
|
2012-06-08 08:11:14 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual void SleepForMicroseconds(int /*micros*/) override {}
|
2012-08-14 22:20:36 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status GetHostName(char* /*name*/, uint64_t /*len*/) override {
|
2015-02-26 19:28:41 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-08-14 22:20:36 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status GetCurrentTime(int64_t* /*unix_time*/) override {
|
|
|
|
return notsup;
|
|
|
|
}
|
2012-08-14 22:20:36 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual Status GetAbsolutePath(const std::string& /*db_path*/,
|
|
|
|
std::string* /*outputpath*/) override {
|
2015-02-26 19:28:41 +00:00
|
|
|
return notsup;
|
|
|
|
}
|
2012-09-19 22:21:09 +00:00
|
|
|
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual void SetBackgroundThreads(int /*number*/,
|
|
|
|
Priority /*pri*/ = LOW) override {}
|
|
|
|
virtual int GetBackgroundThreads(Priority /*pri*/ = LOW) override {
|
|
|
|
return 0;
|
2015-02-26 19:28:41 +00:00
|
|
|
}
|
2017-07-21 21:50:24 +00:00
|
|
|
virtual void IncBackgroundThreadsIfNeeded(int /*number*/,
|
|
|
|
Priority /*pri*/) override {}
|
|
|
|
virtual std::string TimeToString(uint64_t /*number*/) override { return ""; }
|
2015-06-11 21:18:02 +00:00
|
|
|
|
|
|
|
virtual uint64_t GetThreadID() const override {
|
|
|
|
return 0;
|
|
|
|
}
|
2012-06-08 08:11:14 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // USE_HDFS
|