Add support for abortion in v8::OutputStream.
authormikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 14 Sep 2010 15:11:24 +0000 (15:11 +0000)
committermikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 14 Sep 2010 15:11:24 +0000 (15:11 +0000)
It's a good idea to allow receiver to interrupt data transmission.

Review URL: http://codereview.chromium.org/3409002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5452 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8.h
src/profile-generator.cc
src/profile-generator.h
test/cctest/test-heap-profiler.cc

index 03bc401..0613d58 100644 (file)
@@ -3204,6 +3204,10 @@ public:
   enum OutputEncoding {
     kAscii = 0  // 7-bit ASCII.
   };
+  enum WriteResult {
+    kContinue = 0,
+    kAbort = 1
+  };
   virtual ~OutputStream() {}
   /** Notify about the end of stream. */
   virtual void EndOfStream() = 0;
@@ -3211,8 +3215,12 @@ public:
   virtual int GetChunkSize() { return 1024; }
   /** Get preferred output encoding. Called only once. */
   virtual OutputEncoding GetOutputEncoding() { return kAscii; }
-  /** Writes the next chunk of snapshot data into the stream. */
-  virtual void WriteAsciiChunk(char* data, int size) = 0;
+  /**
+   * Writes the next chunk of snapshot data into the stream. Writing
+   * can be stopped by returning kAbort as function result. EndOfStream
+   * will not be called in case writing was aborted.
+   */
+  virtual WriteResult WriteAsciiChunk(char* data, int size) = 0;
 };
 
 
index d974001..71eac3d 100644 (file)
@@ -2140,9 +2140,11 @@ class OutputStreamWriter {
       : stream_(stream),
         chunk_size_(stream->GetChunkSize()),
         chunk_(chunk_size_),
-        chunk_pos_(0) {
+        chunk_pos_(0),
+        aborted_(false) {
     ASSERT(chunk_size_ > 0);
   }
+  bool aborted() { return aborted_; }
   void AddCharacter(char c) {
     ASSERT(c != '\0');
     ASSERT(chunk_pos_ < chunk_size_);
@@ -2170,6 +2172,7 @@ class OutputStreamWriter {
   void AddNumber(unsigned n) { AddNumberImpl<unsigned>(n, "%u"); }
   void AddNumber(uint64_t n) { AddNumberImpl<uint64_t>(n, "%llu"); }
   void Finalize() {
+    if (aborted_) return;
     ASSERT(chunk_pos_ < chunk_size_);
     if (chunk_pos_ != 0) {
       WriteChunk();
@@ -2194,13 +2197,16 @@ class OutputStreamWriter {
     }
   }
   void WriteChunk() {
-    stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_);
+    if (aborted_) return;
+    if (stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_) ==
+        v8::OutputStream::kAbort) aborted_ = true;
   }
 
   v8::OutputStream* stream_;
   int chunk_size_;
   ScopedVector<char> chunk_;
   int chunk_pos_;
+  bool aborted_;
 };
 
 void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
@@ -2210,22 +2216,29 @@ void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
   // Since nodes graph is cyclic, we need the first pass to enumerate
   // them. Strings can be serialized in one pass.
   EnumerateNodes();
+  SerializeImpl();
 
+  delete writer_;
+  writer_ = NULL;
+}
+
+
+void HeapSnapshotJSONSerializer::SerializeImpl() {
   writer_->AddCharacter('{');
   writer_->AddString("\"snapshot\":{");
   SerializeSnapshot();
+  if (writer_->aborted()) return;
   writer_->AddString("},\n");
   writer_->AddString("\"nodes\":[");
   SerializeNodes();
+  if (writer_->aborted()) return;
   writer_->AddString("],\n");
   writer_->AddString("\"strings\":[");
   SerializeStrings();
+  if (writer_->aborted()) return;
   writer_->AddCharacter(']');
   writer_->AddCharacter('}');
   writer_->Finalize();
-
-  delete writer_;
-  writer_ = NULL;
 }
 
 
@@ -2296,6 +2309,7 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
   writer_->AddNumber(children.length());
   for (int i = 0; i < children.length(); ++i) {
     SerializeEdge(&children[i]);
+    if (writer_->aborted()) return;
   }
 }
 
@@ -2363,6 +2377,7 @@ void HeapSnapshotJSONSerializer::SerializeNodes() {
   }
   for (int i = 0; i < sorted_nodes.length(); ++i) {
     SerializeNode(reinterpret_cast<HeapEntry*>(sorted_nodes[i]->key));
+    if (writer_->aborted()) return;
   }
 }
 
@@ -2443,6 +2458,7 @@ void HeapSnapshotJSONSerializer::SerializeStrings() {
     writer_->AddCharacter(',');
     SerializeString(
         reinterpret_cast<const unsigned char*>(sorted_strings[i]->key));
+    if (writer_->aborted()) return;
   }
 }
 
index e5d7f2d..c2bc4ce 100644 (file)
@@ -1003,6 +1003,7 @@ class HeapSnapshotJSONSerializer {
   int GetNodeId(HeapEntry* entry);
   int GetStringId(const char* s);
   void SerializeEdge(HeapGraphEdge* edge);
+  void SerializeImpl();
   void SerializeNode(HeapEntry* entry);
   void SerializeNodes();
   void SerializeSnapshot();
index 2bc52db..5e570f3 100644 (file)
@@ -993,13 +993,18 @@ namespace {
 
 class TestJSONStream : public v8::OutputStream {
  public:
-  TestJSONStream() : eos_signaled_(0) {}
+  TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
+  explicit TestJSONStream(int abort_countdown)
+      : eos_signaled_(0), abort_countdown_(abort_countdown) {}
   virtual ~TestJSONStream() {}
   virtual void EndOfStream() { ++eos_signaled_; }
-  virtual void WriteAsciiChunk(char* buffer, int chars_written) {
+  virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
+    if (abort_countdown_ > 0) --abort_countdown_;
+    if (abort_countdown_ == 0) return kAbort;
     CHECK_GT(chars_written, 0);
     i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
     memcpy(chunk.start(), buffer, chars_written);
+    return kContinue;
   }
   void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
   int eos_signaled() { return eos_signaled_; }
@@ -1007,6 +1012,7 @@ class TestJSONStream : public v8::OutputStream {
  private:
   i::Collector<char> buffer_;
   int eos_signaled_;
+  int abort_countdown_;
 };
 
 class AsciiResource: public v8::String::ExternalAsciiStringResource {
@@ -1123,4 +1129,16 @@ TEST(HeapSnapshotJSONSerialization) {
            *v8::String::Utf8Value(string));
 }
 
+
+TEST(HeapSnapshotJSONSerializationAborting) {
+  v8::HandleScope scope;
+  LocalContext env;
+  const v8::HeapSnapshot* snapshot =
+      v8::HeapProfiler::TakeSnapshot(v8::String::New("abort"));
+  TestJSONStream stream(5);
+  snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
+  CHECK_GT(stream.size(), 0);
+  CHECK_EQ(0, stream.eos_signaled());
+}
+
 #endif  // ENABLE_LOGGING_AND_PROFILING