1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : //
15 : // This file implements the SessionTraceFileWriter and
16 : // SessionTraceFileWriterFactory classes which provide an implementation and
17 : // factory, respectively, for the default buffer consumer used by the call trace
18 : // service.
19 :
20 : #include "syzygy/trace/service/session_trace_file_writer.h"
21 :
22 : #include "base/bind.h"
23 : #include "base/file_util.h"
24 : #include "syzygy/trace/protocol/call_trace_defs.h"
25 : #include "syzygy/trace/service/buffer_pool.h"
26 : #include "syzygy/trace/service/mapped_buffer.h"
27 : #include "syzygy/trace/service/session.h"
28 :
29 : namespace trace {
30 : namespace service {
31 :
32 : SessionTraceFileWriter::SessionTraceFileWriter(
33 : base::MessageLoop* message_loop, const base::FilePath& trace_directory)
34 : : message_loop_(message_loop),
35 E : trace_file_path_(trace_directory) {
36 E : DCHECK(message_loop != NULL);
37 E : DCHECK(!trace_directory.empty());
38 E : }
39 :
40 E : bool SessionTraceFileWriter::Open(Session* session) {
41 E : DCHECK(session != NULL);
42 :
43 E : if (!base::CreateDirectory(trace_file_path_)) {
44 i : LOG(ERROR) << "Failed to create trace directory: '"
45 : << trace_file_path_.value() << "'.";
46 i : return false;
47 : }
48 :
49 : // Append the trace file name onto the trace file directory we stored on
50 : // construction.
51 : base::FilePath basename = TraceFileWriter::GenerateTraceFileBaseName(
52 E : session->client_info());
53 E : trace_file_path_ = trace_file_path_.Append(basename);
54 :
55 : // Open the trace file and write the header.
56 : if (!writer_.Open(trace_file_path_) ||
57 E : !writer_.WriteHeader(session->client_info())) {
58 i : return false;
59 : }
60 :
61 E : return true;
62 E : }
63 :
64 E : bool SessionTraceFileWriter::Close(Session* /* session */) {
65 E : return true;
66 E : }
67 :
68 E : bool SessionTraceFileWriter::ConsumeBuffer(Buffer* buffer) {
69 E : DCHECK(buffer != NULL);
70 E : DCHECK(buffer->session != NULL);
71 E : DCHECK(message_loop_ != NULL);
72 :
73 : message_loop_->PostTask(FROM_HERE,
74 : base::Bind(&SessionTraceFileWriter::WriteBuffer,
75 : this,
76 : scoped_refptr<Session>(buffer->session),
77 E : base::Unretained(buffer)));
78 :
79 E : return true;
80 E : }
81 :
82 E : size_t SessionTraceFileWriter::block_size() const {
83 E : return writer_.block_size();
84 E : }
85 :
86 E : void SessionTraceFileWriter::WriteBuffer(Session* session, Buffer* buffer) {
87 E : DCHECK(session != NULL);
88 E : DCHECK(buffer != NULL);
89 E : DCHECK_EQ(session, buffer->session);
90 E : DCHECK_EQ(Buffer::kPendingWrite, buffer->state);
91 E : DCHECK_EQ(base::MessageLoop::current(), message_loop_);
92 :
93 E : MappedBuffer mapped_buffer(buffer);
94 E : if (!mapped_buffer.Map())
95 i : return;
96 :
97 : // We deliberately ignore the return status. However, this will log if
98 : // anything goes wrong.
99 E : writer_.WriteRecord(mapped_buffer.data(), buffer->buffer_size);
100 :
101 : // It's entirely possible for this buffer to be handed out to another client
102 : // and for the service to be forcibly shutdown before the client has had a
103 : // chance to even touch the buffer. In that case, we'll end up writing the
104 : // buffer again. We clear the RecordPrefix and the TraceFileSegmentHeader so
105 : // that we'll at least see the buffer as empty and write nothing.
106 : ::memset(mapped_buffer.data(), 0,
107 E : sizeof(RecordPrefix) + sizeof(TraceFileSegmentHeader));
108 :
109 E : mapped_buffer.Unmap();
110 E : session->RecycleBuffer(buffer);
111 E : }
112 :
113 : } // namespace service
114 : } // namespace trace
|