diff options
author | 2017-07-25 15:03:34 -0700 | |
---|---|---|
committer | 2017-07-25 15:07:39 -0700 | |
commit | 07249f08867369899d39fc60442febdf1e36e6b5 (patch) | |
tree | d9eca5d534351e2b7ee5e292e05398648650dce9 | |
parent | 6b3751f660dfa0675cc39d163b8224f2c070694e (diff) |
Add LocalTempFilename function to Env class which creates a local temp file name
PiperOrigin-RevId: 163128673
-rw-r--r-- | tensorflow/core/platform/env.cc | 91 | ||||
-rw-r--r-- | tensorflow/core/platform/env.h | 6 | ||||
-rw-r--r-- | tensorflow/core/platform/env_test.cc | 28 |
3 files changed, 125 insertions, 0 deletions
diff --git a/tensorflow/core/platform/env.cc b/tensorflow/core/platform/env.cc index 2fdd989c9b..568a22b295 100644 --- a/tensorflow/core/platform/env.cc +++ b/tensorflow/core/platform/env.cc @@ -13,6 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ +#include <sys/stat.h> #include <deque> #include <utility> #include <vector> @@ -30,7 +31,10 @@ limitations under the License. #include "tensorflow/core/lib/gtl/map_util.h" #include "tensorflow/core/lib/gtl/stl_util.h" #include "tensorflow/core/lib/io/path.h" +#include "tensorflow/core/lib/strings/stringprintf.h" #include "tensorflow/core/platform/env.h" +#include "tensorflow/core/platform/env_time.h" +#include "tensorflow/core/platform/host_info.h" #include "tensorflow/core/platform/protobuf.h" namespace tensorflow { @@ -273,6 +277,93 @@ string Env::GetExecutablePath() { return exe_path; } +bool Env::LocalTempFilename(string* filename) { + std::vector<string> dirs; + GetLocalTempDirectories(&dirs); + + // Try each directory, as they might be full, have inappropriate + // permissions or have different problems at times. + for (const string& dir : dirs) { +#ifdef __APPLE__ + uint64_t tid64; + pthread_threadid_np(nullptr, &tid64); + int32 tid = static_cast<int32>(tid64); + int32 pid = static_cast<int32>(getpid()); +#elif defined(PLATFORM_WINDOWS) + int32 tid = static_cast<int32>(GetCurrentThreadId()); + int32 pid = static_cast<int32>(GetCurrentProcessId()); +#else + int32 tid = static_cast<int32>(pthread_self()); + int32 pid = static_cast<int32>(getpid()); +#endif + uint64 now_microsec = NowMicros(); + + *filename = io::JoinPath( + dir, strings::Printf("tempfile-%s-%x-%d-%llx", port::Hostname().c_str(), + tid, pid, now_microsec)); + if (FileExists(*filename).ok()) { + filename->clear(); + } else { + return true; + } + } + return false; +} + +void Env::GetLocalTempDirectories(std::vector<string>* list) { + list->clear(); +#ifdef PLATFORM_WINDOWS + // On windows we'll try to find a directory in this order: + // C:/Documents & Settings/whomever/TEMP (or whatever GetTempPath() is) + // C:/TMP/ + // C:/TEMP/ + // C:/WINDOWS/ or C:/WINNT/ + // . + char tmp[MAX_PATH]; + // GetTempPath can fail with either 0 or with a space requirement > bufsize. + // See http://msdn.microsoft.com/en-us/library/aa364992(v=vs.85).aspx + DWORD n = GetTempPathA(MAX_PATH, tmp); + if (n > 0 && n <= MAX_PATH) list->push_back(tmp); + list->push_back("C:\\tmp\\"); + list->push_back("C:\\temp\\"); +#else + // Directories, in order of preference. If we find a dir that + // exists, we stop adding other less-preferred dirs + const char* candidates[] = { + // Non-null only during unittest/regtest + getenv("TEST_TMPDIR"), + + // Explicitly-supplied temp dirs + getenv("TMPDIR"), + getenv("TMP"), + + // The old classic tmpdir + "/export/hda3/tmp", + + // If all else fails + "/tmp", + }; + + for (const char* d : candidates) { + if (!d || d[0] == '\0') continue; // Empty env var + + // Make sure we don't surprise anyone who's expecting a '/' + string dstr = d; + if (dstr[dstr.size() - 1] != '/') { + dstr += "/"; + } + + struct stat statbuf; + if (!stat(d, &statbuf) && S_ISDIR(statbuf.st_mode) && + !access(dstr.c_str(), 0)) { + // We found a dir that exists and is accessible - we're done. + list->push_back(dstr); + return; + } + } +#endif +} + Thread::~Thread() {} EnvWrapper::~EnvWrapper() {} diff --git a/tensorflow/core/platform/env.h b/tensorflow/core/platform/env.h index 1b7e024b0f..da8c3e2d7e 100644 --- a/tensorflow/core/platform/env.h +++ b/tensorflow/core/platform/env.h @@ -215,6 +215,9 @@ class Env { /// symlinks if there is any. string GetExecutablePath(); + /// Creates a local unique temporary file name. Returns true if success. + bool LocalTempFilename(string* filename); + // TODO(jeff,sanjay): Add back thread/thread-pool support if needed. // TODO(jeff,sanjay): if needed, tighten spec so relative to epoch, or // provide a routine to get the absolute time. @@ -279,6 +282,9 @@ class Env { const string& version) = 0; private: + // Returns a possible list of local temporary directories. + void GetLocalTempDirectories(std::vector<string>* list); + std::unique_ptr<FileSystemRegistry> file_system_registry_; TF_DISALLOW_COPY_AND_ASSIGN(Env); EnvTime* envTime = EnvTime::Default(); diff --git a/tensorflow/core/platform/env_test.cc b/tensorflow/core/platform/env_test.cc index 7bc1882c86..50dd0cd58b 100644 --- a/tensorflow/core/platform/env_test.cc +++ b/tensorflow/core/platform/env_test.cc @@ -298,4 +298,32 @@ TEST_F(DefaultEnvTest, GetExecutablePath) { TF_EXPECT_OK(env->FileExists(env->GetExecutablePath())); } +TEST_F(DefaultEnvTest, LocalTempFilename) { + Env* env = Env::Default(); + string filename; + EXPECT_TRUE(env->LocalTempFilename(&filename)); + EXPECT_FALSE(env->FileExists(filename).ok()); + + // Write something to the temporary file. + std::unique_ptr<WritableFile> file_to_write; + TF_CHECK_OK(env->NewWritableFile(filename, &file_to_write)); + TF_CHECK_OK(file_to_write->Append("Null")); + TF_CHECK_OK(file_to_write->Close()); + TF_CHECK_OK(env->FileExists(filename)); + + // Read from the temporary file and check content. + std::unique_ptr<RandomAccessFile> file_to_read; + TF_CHECK_OK(env->NewRandomAccessFile(filename, &file_to_read)); + StringPiece content; + char scratch[1024]; + CHECK_EQ(error::OUT_OF_RANGE, + file_to_read->Read(0 /* offset */, 1024 /* n */, &content, scratch) + .code()); + EXPECT_EQ("Null", content.ToString()); + + // Delete the temporary file. + TF_CHECK_OK(env->DeleteFile(filename)); + EXPECT_FALSE(env->FileExists(filename).ok()); +} + } // namespace tensorflow |