Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(274)

Side by Side Diff: webrtc/system_wrappers/source/data_log.cc

Issue 2439473002: Delete DataLog abstraction, which was almost unused. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/system_wrappers/include/data_log.h"
12
13 #include <assert.h>
14
15 #include <algorithm>
16 #include <list>
17
18 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
19 #include "webrtc/system_wrappers/include/event_wrapper.h"
20 #include "webrtc/system_wrappers/include/file_wrapper.h"
21 #include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
22
23 namespace webrtc {
24
25 DataLogImpl::CritSectScopedPtr DataLogImpl::crit_sect_(
26 CriticalSectionWrapper::CreateCriticalSection());
27
28 DataLogImpl* DataLogImpl::instance_ = NULL;
29
30 // A Row contains cells, which are indexed by the column names as std::string.
31 // The string index is treated in a case sensitive way.
32 class Row {
33 public:
34 Row();
35 ~Row();
36
37 // Inserts a Container into the cell of the column specified with
38 // column_name.
39 // column_name is treated in a case sensitive way.
40 int InsertCell(const std::string& column_name,
41 const Container* value_container);
42
43 // Converts the value at the column specified by column_name to a string
44 // stored in value_string.
45 // column_name is treated in a case sensitive way.
46 void ToString(const std::string& column_name, std::string* value_string);
47
48 private:
49 // Collection of containers indexed by column name as std::string
50 typedef std::map<std::string, const Container*> CellMap;
51
52 CellMap cells_;
53 CriticalSectionWrapper* cells_lock_;
54 };
55
56 // A LogTable contains multiple rows, where only the latest row is active for
57 // editing. The rows are defined by the ColumnMap, which contains the name of
58 // each column and the length of the column (1 for one-value-columns and greater
59 // than 1 for multi-value-columns).
60 class LogTable {
61 public:
62 LogTable();
63 ~LogTable();
64
65 // Adds the column with name column_name to the table. The column will be a
66 // multi-value-column if multi_value_length is greater than 1.
67 // column_name is treated in a case sensitive way.
68 int AddColumn(const std::string& column_name, int multi_value_length);
69
70 // Buffers the current row while it is waiting to be written to file,
71 // which is done by a call to Flush(). A new row is available when the
72 // function returns
73 void NextRow();
74
75 // Inserts a Container into the cell of the column specified with
76 // column_name.
77 // column_name is treated in a case sensitive way.
78 int InsertCell(const std::string& column_name,
79 const Container* value_container);
80
81 // Creates a log file, named as specified in the string file_name, to
82 // where the table will be written when calling Flush().
83 int CreateLogFile(const std::string& file_name);
84
85 // Write all complete rows to file.
86 // May not be called by two threads simultaneously (doing so may result in
87 // a race condition). Will be called by the file_writer_thread_ when that
88 // thread is running.
89 void Flush();
90
91 private:
92 // Collection of multi_value_lengths indexed by column name as std::string
93 typedef std::map<std::string, int> ColumnMap;
94 typedef std::list<Row*> RowList;
95
96 ColumnMap columns_;
97 RowList rows_[2];
98 RowList* rows_history_;
99 RowList* rows_flush_;
100 Row* current_row_;
101 FileWrapper* file_;
102 bool write_header_;
103 CriticalSectionWrapper* table_lock_;
104 };
105
106 Row::Row()
107 : cells_(),
108 cells_lock_(CriticalSectionWrapper::CreateCriticalSection()) {
109 }
110
111 Row::~Row() {
112 for (CellMap::iterator it = cells_.begin(); it != cells_.end();) {
113 delete it->second;
114 // For maps all iterators (except the erased) are valid after an erase
115 cells_.erase(it++);
116 }
117 delete cells_lock_;
118 }
119
120 int Row::InsertCell(const std::string& column_name,
121 const Container* value_container) {
122 CriticalSectionScoped synchronize(cells_lock_);
123 assert(cells_.count(column_name) == 0);
124 if (cells_.count(column_name) > 0)
125 return -1;
126 cells_[column_name] = value_container;
127 return 0;
128 }
129
130 void Row::ToString(const std::string& column_name,
131 std::string* value_string) {
132 CriticalSectionScoped synchronize(cells_lock_);
133 const Container* container = cells_[column_name];
134 if (container == NULL) {
135 *value_string = "NaN,";
136 return;
137 }
138 container->ToString(value_string);
139 }
140
141 LogTable::LogTable()
142 : columns_(),
143 rows_(),
144 rows_history_(&rows_[0]),
145 rows_flush_(&rows_[1]),
146 current_row_(new Row),
147 file_(FileWrapper::Create()),
148 write_header_(true),
149 table_lock_(CriticalSectionWrapper::CreateCriticalSection()) {
150 }
151
152 LogTable::~LogTable() {
153 for (RowList::iterator row_it = rows_history_->begin();
154 row_it != rows_history_->end();) {
155 delete *row_it;
156 row_it = rows_history_->erase(row_it);
157 }
158 for (ColumnMap::iterator col_it = columns_.begin();
159 col_it != columns_.end();) {
160 // For maps all iterators (except the erased) are valid after an erase
161 columns_.erase(col_it++);
162 }
163 if (file_ != NULL) {
164 file_->Flush();
165 file_->CloseFile();
166 delete file_;
167 }
168 delete current_row_;
169 delete table_lock_;
170 }
171
172 int LogTable::AddColumn(const std::string& column_name,
173 int multi_value_length) {
174 assert(multi_value_length > 0);
175 if (!write_header_) {
176 // It's not allowed to add new columns after the header
177 // has been written.
178 assert(false);
179 return -1;
180 } else {
181 CriticalSectionScoped synchronize(table_lock_);
182 if (write_header_)
183 columns_[column_name] = multi_value_length;
184 else
185 return -1;
186 }
187 return 0;
188 }
189
190 void LogTable::NextRow() {
191 CriticalSectionScoped sync_rows(table_lock_);
192 rows_history_->push_back(current_row_);
193 current_row_ = new Row;
194 }
195
196 int LogTable::InsertCell(const std::string& column_name,
197 const Container* value_container) {
198 CriticalSectionScoped synchronize(table_lock_);
199 assert(columns_.count(column_name) > 0);
200 if (columns_.count(column_name) == 0)
201 return -1;
202 return current_row_->InsertCell(column_name, value_container);
203 }
204
205 int LogTable::CreateLogFile(const std::string& file_name) {
206 if (file_name.length() == 0)
207 return -1;
208 if (file_->is_open())
209 return -1;
210 // Open with read/write permissions
211 return file_->OpenFile(file_name.c_str(), false) ? 0 : -1;
212 }
213
214 void LogTable::Flush() {
215 ColumnMap::iterator column_it;
216 bool commit_header = false;
217 if (write_header_) {
218 CriticalSectionScoped synchronize(table_lock_);
219 if (write_header_) {
220 commit_header = true;
221 write_header_ = false;
222 }
223 }
224 if (commit_header) {
225 for (column_it = columns_.begin();
226 column_it != columns_.end(); ++column_it) {
227 if (column_it->second > 1) {
228 file_->WriteText("%s[%u],", column_it->first.c_str(),
229 column_it->second);
230 for (int i = 1; i < column_it->second; ++i)
231 file_->WriteText(",");
232 } else {
233 file_->WriteText("%s,", column_it->first.c_str());
234 }
235 }
236 if (columns_.size() > 0)
237 file_->WriteText("\n");
238 }
239
240 // Swap the list used for flushing with the list containing the row history
241 // and clear the history. We also create a local pointer to the new
242 // list used for flushing to avoid race conditions if another thread
243 // calls this function while we are writing.
244 // We don't want to block the list while we're writing to file.
245 {
246 CriticalSectionScoped synchronize(table_lock_);
247 RowList* tmp = rows_flush_;
248 rows_flush_ = rows_history_;
249 rows_history_ = tmp;
250 rows_history_->clear();
251 }
252
253 // Write all complete rows to file and delete them
254 for (RowList::iterator row_it = rows_flush_->begin();
255 row_it != rows_flush_->end();) {
256 for (column_it = columns_.begin();
257 column_it != columns_.end(); ++column_it) {
258 std::string row_string;
259 (*row_it)->ToString(column_it->first, &row_string);
260 file_->WriteText("%s", row_string.c_str());
261 }
262 if (columns_.size() > 0)
263 file_->WriteText("\n");
264 delete *row_it;
265 row_it = rows_flush_->erase(row_it);
266 }
267 }
268
269 int DataLog::CreateLog() {
270 return DataLogImpl::CreateLog();
271 }
272
273 void DataLog::ReturnLog() {
274 return DataLogImpl::ReturnLog();
275 }
276
277 std::string DataLog::Combine(const std::string& table_name, int table_id) {
278 std::stringstream ss;
279 std::string combined_id = table_name;
280 std::string number_suffix;
281 ss << "_" << table_id;
282 ss >> number_suffix;
283 combined_id += number_suffix;
284 std::transform(combined_id.begin(), combined_id.end(), combined_id.begin(),
285 ::tolower);
286 return combined_id;
287 }
288
289 int DataLog::AddTable(const std::string& table_name) {
290 DataLogImpl* data_log = DataLogImpl::StaticInstance();
291 if (data_log == NULL)
292 return -1;
293 return data_log->AddTable(table_name);
294 }
295
296 int DataLog::AddColumn(const std::string& table_name,
297 const std::string& column_name,
298 int multi_value_length) {
299 DataLogImpl* data_log = DataLogImpl::StaticInstance();
300 if (data_log == NULL)
301 return -1;
302 return data_log->DataLogImpl::StaticInstance()->AddColumn(table_name,
303 column_name,
304 multi_value_length);
305 }
306
307 int DataLog::NextRow(const std::string& table_name) {
308 DataLogImpl* data_log = DataLogImpl::StaticInstance();
309 if (data_log == NULL)
310 return -1;
311 return data_log->DataLogImpl::StaticInstance()->NextRow(table_name);
312 }
313
314 DataLogImpl::DataLogImpl()
315 : counter_(1),
316 tables_(),
317 flush_event_(EventWrapper::Create()),
318 file_writer_thread_(
319 new rtc::PlatformThread(DataLogImpl::Run, instance_, "DataLog")),
320 tables_lock_(RWLockWrapper::CreateRWLock()) {}
321
322 DataLogImpl::~DataLogImpl() {
323 StopThread();
324 Flush(); // Write any remaining rows
325 delete flush_event_;
326 for (TableMap::iterator it = tables_.begin(); it != tables_.end();) {
327 delete static_cast<LogTable*>(it->second);
328 // For maps all iterators (except the erased) are valid after an erase
329 tables_.erase(it++);
330 }
331 delete tables_lock_;
332 }
333
334 int DataLogImpl::CreateLog() {
335 CriticalSectionScoped synchronize(crit_sect_.get());
336 if (instance_ == NULL) {
337 instance_ = new DataLogImpl();
338 return instance_->Init();
339 } else {
340 ++instance_->counter_;
341 }
342 return 0;
343 }
344
345 int DataLogImpl::Init() {
346 file_writer_thread_->Start();
347 file_writer_thread_->SetPriority(rtc::kHighestPriority);
348 return 0;
349 }
350
351 DataLogImpl* DataLogImpl::StaticInstance() {
352 return instance_;
353 }
354
355 void DataLogImpl::ReturnLog() {
356 CriticalSectionScoped synchronize(crit_sect_.get());
357 if (instance_ && instance_->counter_ > 1) {
358 --instance_->counter_;
359 return;
360 }
361 delete instance_;
362 instance_ = NULL;
363 }
364
365 int DataLogImpl::AddTable(const std::string& table_name) {
366 WriteLockScoped synchronize(*tables_lock_);
367 // Make sure we don't add a table which already exists
368 if (tables_.count(table_name) > 0)
369 return -1;
370 tables_[table_name] = new LogTable();
371 if (tables_[table_name]->CreateLogFile(table_name + ".txt") == -1)
372 return -1;
373 return 0;
374 }
375
376 int DataLogImpl::AddColumn(const std::string& table_name,
377 const std::string& column_name,
378 int multi_value_length) {
379 ReadLockScoped synchronize(*tables_lock_);
380 if (tables_.count(table_name) == 0)
381 return -1;
382 return tables_[table_name]->AddColumn(column_name, multi_value_length);
383 }
384
385 int DataLogImpl::InsertCell(const std::string& table_name,
386 const std::string& column_name,
387 const Container* value_container) {
388 ReadLockScoped synchronize(*tables_lock_);
389 assert(tables_.count(table_name) > 0);
390 if (tables_.count(table_name) == 0)
391 return -1;
392 return tables_[table_name]->InsertCell(column_name, value_container);
393 }
394
395 int DataLogImpl::NextRow(const std::string& table_name) {
396 ReadLockScoped synchronize(*tables_lock_);
397 if (tables_.count(table_name) == 0)
398 return -1;
399 tables_[table_name]->NextRow();
400 // Signal a complete row
401 flush_event_->Set();
402 return 0;
403 }
404
405 void DataLogImpl::Flush() {
406 ReadLockScoped synchronize(*tables_lock_);
407 for (TableMap::iterator it = tables_.begin(); it != tables_.end(); ++it) {
408 it->second->Flush();
409 }
410 }
411
412 bool DataLogImpl::Run(void* obj) {
413 static_cast<DataLogImpl*>(obj)->Process();
414 return true;
415 }
416
417 void DataLogImpl::Process() {
418 // Wait for a row to be complete
419 flush_event_->Wait(WEBRTC_EVENT_INFINITE);
420 Flush();
421 }
422
423 void DataLogImpl::StopThread() {
424 flush_event_->Set();
425 file_writer_thread_->Stop();
426 }
427
428 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/system_wrappers/include/data_log_impl.h ('k') | webrtc/system_wrappers/source/data_log_c.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698