#include <stddef.h> // for NULL
+#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/lib/strings/strcat.h"
file_prefix_(file_prefix),
num_outstanding_events_(0) {}
-bool EventsWriter::InitIfNeeded() {
+EventsWriter::~EventsWriter() {
+ Close().IgnoreError(); // Autoclose in destructor.
+}
+
+Status EventsWriter::Init() { return InitWithSuffix(""); }
+
+Status EventsWriter::InitWithSuffix(const string& suffix) {
+ file_suffix_ = suffix;
+ return InitIfNeeded();
+}
+
+Status EventsWriter::InitIfNeeded() {
if (recordio_writer_ != nullptr) {
CHECK(!filename_.empty());
- if (FileHasDisappeared()) {
+ if (!FileStillExists().ok()) {
// Warn user of data loss and let .reset() below do basic cleanup.
if (num_outstanding_events_ > 0) {
LOG(WARNING) << "Re-initialization, attempting to open a new file, "
}
} else {
// No-op: File is present and writer is initialized.
- return true;
+ return Status::OK();
}
}
static_cast<int64>(time_in_seconds),
port::Hostname().c_str(), file_suffix_.c_str());
- Status s = env_->NewWritableFile(filename_, &recordio_file_);
- if (!s.ok()) {
- LOG(ERROR) << "Could not open events file: " << filename_ << ": " << s;
- return false;
- }
+ TF_RETURN_WITH_CONTEXT_IF_ERROR(
+ env_->NewWritableFile(filename_, &recordio_file_),
+ "Creating writable file ", filename_);
recordio_writer_.reset(new io::RecordWriter(recordio_file_.get()));
if (recordio_writer_ == nullptr) {
- LOG(ERROR) << "Could not create record writer";
- return false;
+ return errors::Unknown("Could not create record writer");
}
num_outstanding_events_ = 0;
VLOG(1) << "Successfully opened events file: " << filename_;
event.set_wall_time(time_in_seconds);
event.set_file_version(strings::StrCat(kVersionPrefix, kCurrentVersion));
WriteEvent(event);
- Flush();
+ TF_RETURN_WITH_CONTEXT_IF_ERROR(Flush(), "Flushing first event.");
}
- return true;
+ return Status::OK();
}
string EventsWriter::FileName() {
if (filename_.empty()) {
- InitIfNeeded();
+ InitIfNeeded().IgnoreError();
}
return filename_;
}
void EventsWriter::WriteSerializedEvent(StringPiece event_str) {
if (recordio_writer_ == nullptr) {
- if (!InitIfNeeded()) {
+ if (!InitIfNeeded().ok()) {
LOG(ERROR) << "Write failed because file could not be opened.";
return;
}
WriteSerializedEvent(record);
}
-bool EventsWriter::Flush() {
- if (num_outstanding_events_ == 0) return true;
+Status EventsWriter::Flush() {
+ if (num_outstanding_events_ == 0) return Status::OK();
CHECK(recordio_file_ != nullptr) << "Unexpected NULL file";
- if (!recordio_writer_->Flush().ok()) {
- LOG(ERROR) << "Failed to flush " << num_outstanding_events_ << " events to "
- << filename_;
- return false;
- }
+ TF_RETURN_WITH_CONTEXT_IF_ERROR(recordio_writer_->Flush(), "Failed to flush ",
+ num_outstanding_events_, " to ", filename_);
+ TF_RETURN_WITH_CONTEXT_IF_ERROR(recordio_file_->Sync(), "Failed to sync ",
+ num_outstanding_events_, " to ", filename_);
- // The FileHasDisappeared() condition is necessary because
- // recordio_writer_->Sync() can return true even if the underlying
+ // The FileStillExists() condition is necessary because
+ // recordio_writer_->Sync() can return OK even if the underlying
// file has been deleted. EventWriter.FileDeletionBeforeWriting
// demonstrates this and will fail if the FileHasDisappeared()
// condition is removed.
// Also, we deliberately attempt to Sync() before checking for a
// disappearing file, in case for some file system File::Exists() is
// false after File::Open() but before File::Sync().
- if (!recordio_file_->Flush().ok() || !recordio_file_->Sync().ok() ||
- FileHasDisappeared()) {
- LOG(ERROR) << "Failed to flush " << num_outstanding_events_ << " events to "
- << filename_;
- return false;
- }
+ TF_RETURN_WITH_CONTEXT_IF_ERROR(FileStillExists(), "Failed to flush ",
+ num_outstanding_events_, " to ", filename_);
VLOG(1) << "Wrote " << num_outstanding_events_ << " events to disk.";
num_outstanding_events_ = 0;
- return true;
+ return Status::OK();
}
-bool EventsWriter::Close() {
- bool return_value = Flush();
+Status EventsWriter::Close() {
+ Status status = Flush();
if (recordio_file_ != nullptr) {
- Status s = recordio_file_->Close();
- if (!s.ok()) {
- LOG(ERROR) << "Error when closing previous event file: " << filename_
- << ": " << s;
- return_value = false;
+ Status close_status = recordio_file_->Close();
+ if (!close_status.ok()) {
+ status = close_status;
}
recordio_writer_.reset(nullptr);
recordio_file_.reset(nullptr);
}
num_outstanding_events_ = 0;
- return return_value;
+ return status;
}
-bool EventsWriter::FileHasDisappeared() {
+Status EventsWriter::FileStillExists() {
if (env_->FileExists(filename_).ok()) {
- return false;
- } else {
- // This can happen even with non-null recordio_writer_ if some other
- // process has removed the file.
- LOG(ERROR) << "The events file " << filename_ << " has disappeared.";
- return true;
+ return Status::OK();
}
+ // This can happen even with non-null recordio_writer_ if some other
+ // process has removed the file.
+ return errors::Unknown("The events file ", filename_, " has disappeared.");
}
} // namespace tensorflow
#include <memory>
#include <string>
+
+#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/io/record_writer.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/macros.h"
// Note that it is not recommended to simultaneously have two
// EventWriters writing to the same file_prefix.
explicit EventsWriter(const string& file_prefix);
- ~EventsWriter() { Close(); } // Autoclose in destructor.
+ ~EventsWriter();
// Sets the event file filename and opens file for writing. If not called by
// user, will be invoked automatically by a call to FileName() or Write*().
// and is open this is a no-op. If on the other hand the file was opened,
// but has since disappeared (e.g. deleted by another process), this will open
// a new file with a new timestamp in its filename.
- bool Init() { return InitWithSuffix(""); }
- bool InitWithSuffix(const string& suffix) {
- file_suffix_ = suffix;
- return InitIfNeeded();
- }
+ Status Init();
+ Status InitWithSuffix(const string& suffix);
// Returns the filename for the current events file:
// filename_ = [file_prefix_].out.events.[timestamp].[hostname][suffix]
// be written too.
// Close() calls Flush() and then closes the current events file.
// Returns true only if both the flush and the closure were successful.
- bool Flush();
- bool Close();
+ Status Flush();
+ Status Close();
private:
- bool FileHasDisappeared(); // True if event_file_path_ does not exist.
- bool InitIfNeeded();
+ Status FileStillExists(); // OK if event_file_path_ exists.
+ Status InitIfNeeded();
Env* env_;
const string file_prefix_;
string file_prefix = GetDirName("/writeflush_test");
EventsWriter writer(file_prefix);
WriteFile(&writer);
- EXPECT_TRUE(writer.Flush());
+ TF_EXPECT_OK(writer.Flush());
string filename = writer.FileName();
VerifyFile(filename);
}
string file_prefix = GetDirName("/writeclose_test");
EventsWriter writer(file_prefix);
WriteFile(&writer);
- EXPECT_TRUE(writer.Close());
+ TF_EXPECT_OK(writer.Close());
string filename = writer.FileName();
VerifyFile(filename);
}
TF_EXPECT_OK(env()->FileExists(filename));
TF_ASSERT_OK(env()->DeleteFile(filename));
EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code());
- EXPECT_FALSE(writer.Flush());
+ EXPECT_FALSE(writer.Flush().ok());
EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code());
}
TF_EXPECT_OK(env()->FileExists(filename));
TF_ASSERT_OK(env()->DeleteFile(filename));
EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code());
- EXPECT_FALSE(writer.Close());
+ EXPECT_FALSE(writer.Close().ok());
EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code());
}
TEST(EventWriter, InitWriteClose) {
string file_prefix = GetDirName("/initwriteclose_test");
EventsWriter writer(file_prefix);
- EXPECT_TRUE(writer.Init());
+ TF_EXPECT_OK(writer.Init());
string filename0 = writer.FileName();
TF_EXPECT_OK(env()->FileExists(filename0));
WriteFile(&writer);
- EXPECT_TRUE(writer.Close());
+ TF_EXPECT_OK(writer.Close());
string filename1 = writer.FileName();
EXPECT_EQ(filename0, filename1);
VerifyFile(filename1);
string filename = writer.FileName();
TF_EXPECT_OK(env()->FileExists(filename));
WriteFile(&writer);
- EXPECT_TRUE(writer.Close());
+ TF_EXPECT_OK(writer.Close());
VerifyFile(filename);
}
string file_prefix = GetDirName("/nameclose_test");
EventsWriter writer(file_prefix);
string filename = writer.FileName();
- EXPECT_TRUE(writer.Close());
+ TF_EXPECT_OK(writer.Close());
TF_EXPECT_OK(env()->FileExists(filename));
TF_ASSERT_OK(env()->DeleteFile(filename));
}
env()->SleepForMicroseconds(
2000000); // To make sure timestamp part of filename will differ.
TF_ASSERT_OK(env()->DeleteFile(filename0));
- EXPECT_TRUE(writer.Init()); // Init should reopen file.
+ TF_EXPECT_OK(writer.Init()); // Init should reopen file.
WriteFile(&writer);
- EXPECT_TRUE(writer.Flush());
+ TF_EXPECT_OK(writer.Flush());
string filename1 = writer.FileName();
EXPECT_NE(filename0, filename1);
VerifyFile(filename1);