aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Yuefeng Zhou <yuefengz@google.com>2017-07-25 15:03:34 -0700
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2017-07-25 15:07:39 -0700
commit07249f08867369899d39fc60442febdf1e36e6b5 (patch)
treed9eca5d534351e2b7ee5e292e05398648650dce9
parent6b3751f660dfa0675cc39d163b8224f2c070694e (diff)
Add LocalTempFilename function to Env class which creates a local temp file name
PiperOrigin-RevId: 163128673
-rw-r--r--tensorflow/core/platform/env.cc91
-rw-r--r--tensorflow/core/platform/env.h6
-rw-r--r--tensorflow/core/platform/env_test.cc28
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