Add support for a numeric table id in DataLogs.

Useful when logging in modules which have multiple instances and the logs
should be separated into different tables.
Review URL: http://webrtc-codereview.appspot.com/132003

git-svn-id: http://webrtc.googlecode.com/svn/trunk@555 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2011-09-07 15:31:03 +00:00
parent dd07d5932a
commit 3bbe41aad6
5 changed files with 89 additions and 91 deletions

View File

@ -53,26 +53,29 @@ class DataLog {
// CreateLog or memory leak will occur. // CreateLog or memory leak will occur.
static void ReturnLog(); static void ReturnLog();
// Adds a new table, with the name table_name, and creates the file, with // Combines the string table_name and the integer table_id into a new string
// the name file_name, to which the table will be written. // table_name + _ + table_id. The new string will be lower-case.
// table_name is case sensitive. static std::string Combine(const std::string& table_name, int table_id);
static int AddTable(const std::string& table_name,
const std::string& file_name); // Adds a new table, with the name table_name, and creates the file, with the
// name table_name + ".txt", to which the table will be written.
// table_name is treated in a case sensitive way.
static int AddTable(const std::string& table_name);
// Adds a new column to a table. The column will be a multi-value-column // Adds a new column to a table. The column will be a multi-value-column
// if multi_value_length is greater than 1. // if multi_value_length is greater than 1.
// Both table_name and column_name are case sensitive. // table_name and column_name are treated in a case sensitive way.
static int AddColumn(const std::string& table_name, static int AddColumn(const std::string& table_name,
const std::string& column_name, const std::string& column_name,
int multi_value_length); int multi_value_length);
// Inserts a single value into a table with name table_name at the column // Inserts a single value into a table with name table_name at the column with
// with name column_name. // name column_name.
// Note that the ValueContainer makes use of the copy constructor, // Note that the ValueContainer makes use of the copy constructor,
// operator= and operator<< of the type T, and that the template type must // operator= and operator<< of the type T, and that the template type must
// implement a deep copy copy constructor and operator=. // implement a deep copy copy constructor and operator=.
// Copy constructor and operator= must not be disabled for the type T. // Copy constructor and operator= must not be disabled for the type T.
// Both table_name and column_name are case sensitive. // table_name and column_name are treated in a case sensitive way.
template<class T> template<class T>
static int InsertCell(const std::string& table_name, static int InsertCell(const std::string& table_name,
const std::string& column_name, const std::string& column_name,
@ -92,7 +95,7 @@ class DataLog {
// operator= and operator<< of the type T, and that the template type // operator= and operator<< of the type T, and that the template type
// must implement a deep copy copy constructor and operator=. // must implement a deep copy copy constructor and operator=.
// Copy constructor and operator= must not be disabled for the type T. // Copy constructor and operator= must not be disabled for the type T.
// Both table_name and column_name are case sensitive. // table_name and column_name are treated in a case sensitive way.
template<class T> template<class T>
static int InsertCell(const std::string& table_name, static int InsertCell(const std::string& table_name,
const std::string& column_name, const std::string& column_name,
@ -107,9 +110,9 @@ class DataLog {
new MultiValueContainer<T>(array, length)); new MultiValueContainer<T>(array, length));
} }
// For the table table_name: Writes the current row to file. Starts a new // For the table with name table_name: Writes the current row to file.
// empty row. // Starts a new empty row.
// table_name is case sensitive. // table_name is treated in a case-sensitive way.
static int NextRow(const std::string& table_name); static int NextRow(const std::string& table_name);
}; };

View File

@ -83,47 +83,37 @@ class DataLogImpl {
public: public:
~DataLogImpl(); ~DataLogImpl();
// Creates a log which uses a separate thread (referred to as the file // The implementation of the CreateLog() method declared in data_log.h.
// writer thread) for writing log rows to file. // See data_log.h for a description.
//
// Calls to this function after the log object has been created will only
// increment the reference counter.
static int CreateLog(); static int CreateLog();
// Returns a pointer to the instance of DataLogImpl which was created by // The implementation of the StaticInstance() method declared in data_log.h.
// CreateLog(), or NULL if no instance has been created, or if the // See data_log.h for a description.
// previous instance has been deleted.
static DataLogImpl* StaticInstance(); static DataLogImpl* StaticInstance();
// Decrements the reference counter keeping track of the number of times // The implementation of the ReturnLog() method declared in data_log.h. See
// CreateLog() has been called. When the reference counter reaches 0 // data_log.h for a description.
// the DataLogImpl instance created by CreateLog() will be deleted.
// Should be called equal number of times as successful calls to
// CreateLog or memory leak will occur.
static void ReturnLog(); static void ReturnLog();
// Adds a new table, with the name table_name, and creates the file, with // The implementation of the AddTable() method declared in data_log.h. See
// the name file_name, to which the table will be written. // data_log.h for a description.
// table_name is case sensitive. int AddTable(const std::string& table_name);
int AddTable(const std::string& table_name, const std::string& file_name);
// Adds a new column to a table. The column will be a multi-value-column // The implementation of the AddColumn() method declared in data_log.h. See
// if multi_value_length is greater than 1. // data_log.h for a description.
// Both table_name and column_name are case sensitive.
int AddColumn(const std::string& table_name, int AddColumn(const std::string& table_name,
const std::string& column_name, const std::string& column_name,
int multi_value_length); int multi_value_length);
// Inserts a Container into a table with name table_name at the column // Inserts a Container into a table with name table_name at the column
// with name column_name. // with name column_name.
// Both table_name and column_name are case sensitive. // column_name is treated in a case sensitive way.
int InsertCell(const std::string& table_name, int InsertCell(const std::string& table_name,
const std::string& column_name, const std::string& column_name,
const Container* value_container); const Container* value_container);
// For the table table_name: Writes the current row to file. Starts a new // The implementation of the NextRow() method declared in data_log.h. See
// empty row. // data_log.h for a description.
// table_name is case sensitive.
int NextRow(const std::string& table_name); int NextRow(const std::string& table_name);
private: private:
@ -149,7 +139,7 @@ class DataLogImpl {
// Stops the continuous calling of Process(). // Stops the continuous calling of Process().
void StopThread(); void StopThread();
// Collection of tables indexed by table name as std::string // Collection of tables indexed by the table name as std::string.
typedef std::map<std::string, LogTable*> TableMap; typedef std::map<std::string, LogTable*> TableMap;
typedef webrtc::scoped_ptr<CriticalSectionWrapper> CritSectScopedPtr; typedef webrtc::scoped_ptr<CriticalSectionWrapper> CritSectScopedPtr;

View File

@ -12,6 +12,7 @@
#include <assert.h> #include <assert.h>
#include <algorithm>
#include <list> #include <list>
#include "critical_section_wrapper.h" #include "critical_section_wrapper.h"
@ -28,7 +29,7 @@ DataLogImpl::CritSectScopedPtr DataLogImpl::crit_sect_(
DataLogImpl* DataLogImpl::instance_ = NULL; DataLogImpl* DataLogImpl::instance_ = NULL;
// A Row contains cells, which are indexed by the column names as std::string. // A Row contains cells, which are indexed by the column names as std::string.
// The string index is case sensitive. // The string index is treated in a case sensitive way.
class Row { class Row {
public: public:
Row(); Row();
@ -36,13 +37,13 @@ class Row {
// Inserts a Container into the cell of the column specified with // Inserts a Container into the cell of the column specified with
// column_name. // column_name.
// column_name is case sensitive. // column_name is treated in a case sensitive way.
int InsertCell(const std::string& column_name, int InsertCell(const std::string& column_name,
const Container* value_container); const Container* value_container);
// Converts the value at the column specified by column_name to a string // Converts the value at the column specified by column_name to a string
// stored in value_string. // stored in value_string.
// column_name is case sensitive. // column_name is treated in a case sensitive way.
void ToString(const std::string& column_name, std::string* value_string); void ToString(const std::string& column_name, std::string* value_string);
private: private:
@ -64,7 +65,7 @@ class LogTable {
// Adds the column with name column_name to the table. The column will be a // Adds the column with name column_name to the table. The column will be a
// multi-value-column if multi_value_length is greater than 1. // multi-value-column if multi_value_length is greater than 1.
// column_name is case sensitive. // column_name is treated in a case sensitive way.
int AddColumn(const std::string& column_name, int multi_value_length); int AddColumn(const std::string& column_name, int multi_value_length);
// Buffers the current row while it is waiting to be written to file, // Buffers the current row while it is waiting to be written to file,
@ -74,7 +75,7 @@ class LogTable {
// Inserts a Container into the cell of the column specified with // Inserts a Container into the cell of the column specified with
// column_name. // column_name.
// column_name is case sensitive. // column_name is treated in a case sensitive way.
int InsertCell(const std::string& column_name, int InsertCell(const std::string& column_name,
const Container* value_container); const Container* value_container);
@ -280,12 +281,21 @@ void DataLog::ReturnLog() {
return DataLogImpl::ReturnLog(); return DataLogImpl::ReturnLog();
} }
int DataLog::AddTable(const std::string& table_name, std::string DataLog::Combine(const std::string& table_name, int table_id) {
const std::string& file_name) { std::stringstream ss;
std::string combined_id;
ss << table_name << "_" << table_id;
ss >> combined_id;
std::transform(combined_id.begin(), combined_id.end(), combined_id.begin(),
::tolower);
return combined_id;
}
int DataLog::AddTable(const std::string& table_name) {
DataLogImpl* data_log = DataLogImpl::StaticInstance(); DataLogImpl* data_log = DataLogImpl::StaticInstance();
if (data_log == NULL) if (data_log == NULL)
return -1; return -1;
return data_log->AddTable(table_name, file_name); return data_log->AddTable(table_name);
} }
int DataLog::AddColumn(const std::string& table_name, int DataLog::AddColumn(const std::string& table_name,
@ -367,14 +377,13 @@ void DataLogImpl::ReturnLog() {
instance_ = NULL; instance_ = NULL;
} }
int DataLogImpl::AddTable(const std::string& table_name, int DataLogImpl::AddTable(const std::string& table_name) {
const std::string& file_name) {
WriteLockScoped synchronize(*tables_lock_); WriteLockScoped synchronize(*tables_lock_);
// Make sure we don't add a table which already exists // Make sure we don't add a table which already exists
if (tables_.count(table_name) > 0) if (tables_.count(table_name) > 0)
return -1; return -1;
tables_[table_name] = new LogTable(); tables_[table_name] = new LogTable();
if (tables_[table_name]->CreateLogFile(file_name) == -1) if (tables_[table_name]->CreateLogFile(table_name + ".txt") == -1)
return -1; return -1;
return 0; return 0;
} }

View File

@ -19,8 +19,7 @@ int DataLog::CreateLog() {
void DataLog::ReturnLog() { void DataLog::ReturnLog() {
} }
int DataLog::AddTable(const std::string& /*table_name*/, int DataLog::AddTable(const std::string& /*table_name*/) {
const std::string& /*file_name*/) {
return 0; return 0;
} }
@ -47,8 +46,7 @@ DataLogImpl* DataLogImpl::StaticInstance() {
void DataLogImpl::ReturnLog() { void DataLogImpl::ReturnLog() {
} }
int DataLogImpl::AddTable(const std::string& /*table_name*/, int DataLogImpl::AddTable(const std::string& /*table_name*/) {
const std::string& /*file_name*/) {
return 0; return 0;
} }

View File

@ -113,29 +113,30 @@ class DataLogParser {
TEST(TestDataLog, CreateReturnTest) { TEST(TestDataLog, CreateReturnTest) {
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
ASSERT_EQ(DataLog::CreateLog(), 0); ASSERT_EQ(DataLog::CreateLog(), 0);
ASSERT_EQ(DataLog::AddTable("a proper table", "table.txt"), 0); ASSERT_EQ(DataLog::AddTable(DataLog::Combine("a proper table", 1)), 0);
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
DataLog::ReturnLog(); DataLog::ReturnLog();
ASSERT_LT(DataLog::AddTable("table failure", "table.txt"), 0); ASSERT_LT(DataLog::AddTable(DataLog::Combine("table failure", 1)), 0);
} }
TEST(TestDataLog, VerifySingleTable) { TEST(TestDataLog, VerifySingleTable) {
DataLog::CreateLog(); DataLog::CreateLog();
DataLog::AddTable("table1", "table1.txt"); DataLog::AddTable(DataLog::Combine("table", 1));
DataLog::AddColumn("table1", "arrival", 1); DataLog::AddColumn(DataLog::Combine("table", 1), "arrival", 1);
DataLog::AddColumn("table1", "timestamp", 1); DataLog::AddColumn(DataLog::Combine("table", 1), "timestamp", 1);
DataLog::AddColumn("table1", "size", 5); DataLog::AddColumn(DataLog::Combine("table", 1), "size", 5);
WebRtc_UWord32 sizes[5] = {1400, 1500, 1600, 1700, 1800}; WebRtc_UWord32 sizes[5] = {1400, 1500, 1600, 1700, 1800};
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
DataLog::InsertCell("table1", "arrival", static_cast<double>(i)); DataLog::InsertCell(DataLog::Combine("table", 1), "arrival",
DataLog::InsertCell("table1", "timestamp", static_cast<double>(i));
DataLog::InsertCell(DataLog::Combine("table", 1), "timestamp",
static_cast<WebRtc_Word64>(4354 + i)); static_cast<WebRtc_Word64>(4354 + i));
DataLog::InsertCell("table1", "size", sizes, 5); DataLog::InsertCell(DataLog::Combine("table", 1), "size", sizes, 5);
DataLog::NextRow("table1"); DataLog::NextRow(DataLog::Combine("table", 1));
} }
DataLog::ReturnLog(); DataLog::ReturnLog();
// Verify file // Verify file
FILE* table = fopen("table1.txt", "r"); FILE* table = fopen("table_1.txt", "r");
ASSERT_FALSE(table == NULL); ASSERT_FALSE(table == NULL);
// Read the column names and verify with the expected columns. // Read the column names and verify with the expected columns.
// Note that the columns are written to file in alphabetical order. // Note that the columns are written to file in alphabetical order.
@ -170,31 +171,31 @@ TEST(TestDataLog, VerifySingleTable) {
TEST(TestDataLog, VerifyMultipleTables) { TEST(TestDataLog, VerifyMultipleTables) {
DataLog::CreateLog(); DataLog::CreateLog();
DataLog::AddTable("table2", "table2.txt"); DataLog::AddTable(DataLog::Combine("table", 2));
DataLog::AddTable("table3", "table3.txt"); DataLog::AddTable(DataLog::Combine("table", 3));
DataLog::AddColumn("table2", "arrival", 1); DataLog::AddColumn(DataLog::Combine("table", 2), "arrival", 1);
DataLog::AddColumn("table2", "timestamp", 1); DataLog::AddColumn(DataLog::Combine("table", 2), "timestamp", 1);
DataLog::AddColumn("table2", "size", 1); DataLog::AddColumn(DataLog::Combine("table", 2), "size", 1);
DataLog::AddTable("table4", "table4.txt"); DataLog::AddTable(DataLog::Combine("table", 4));
DataLog::AddColumn("table3", "timestamp", 1); DataLog::AddColumn(DataLog::Combine("table", 3), "timestamp", 1);
DataLog::AddColumn("table3", "arrival", 1); DataLog::AddColumn(DataLog::Combine("table", 3), "arrival", 1);
DataLog::AddColumn("table4", "size", 1); DataLog::AddColumn(DataLog::Combine("table", 4), "size", 1);
for (WebRtc_Word32 i = 0; i < 10; ++i) { for (WebRtc_Word32 i = 0; i < 10; ++i) {
DataLog::InsertCell("table2", "arrival", DataLog::InsertCell(DataLog::Combine("table", 2), "arrival",
static_cast<WebRtc_Word32>(i)); static_cast<WebRtc_Word32>(i));
DataLog::InsertCell("table2", "timestamp", DataLog::InsertCell(DataLog::Combine("table", 2), "timestamp",
static_cast<WebRtc_Word32>(4354 + i)); static_cast<WebRtc_Word32>(4354 + i));
DataLog::InsertCell("table2", "size", DataLog::InsertCell(DataLog::Combine("table", 2), "size",
static_cast<WebRtc_Word32>(1200 + 10 * i)); static_cast<WebRtc_Word32>(1200 + 10 * i));
DataLog::InsertCell("table3", "timestamp", DataLog::InsertCell(DataLog::Combine("table", 3), "timestamp",
static_cast<WebRtc_Word32>(4354 + i)); static_cast<WebRtc_Word32>(4354 + i));
DataLog::InsertCell("table3", "arrival", DataLog::InsertCell(DataLog::Combine("table", 3), "arrival",
static_cast<WebRtc_Word32>(i)); static_cast<WebRtc_Word32>(i));
DataLog::InsertCell("table4", "size", DataLog::InsertCell(DataLog::Combine("table", 4), "size",
static_cast<WebRtc_Word32>(1200 + 10 * i)); static_cast<WebRtc_Word32>(1200 + 10 * i));
DataLog::NextRow("table4"); DataLog::NextRow(DataLog::Combine("table", 4));
DataLog::NextRow("table2"); DataLog::NextRow(DataLog::Combine("table", 2));
DataLog::NextRow("table3"); DataLog::NextRow(DataLog::Combine("table", 3));
} }
DataLog::ReturnLog(); DataLog::ReturnLog();
@ -217,7 +218,7 @@ TEST(TestDataLog, VerifyMultipleTables) {
// Verify table 2 // Verify table 2
{ {
FILE* table = fopen("table2.txt", "r"); FILE* table = fopen("table_2.txt", "r");
ASSERT_FALSE(table == NULL); ASSERT_FALSE(table == NULL);
ExpectedValuesMap expected; ExpectedValuesMap expected;
expected["arrival,"] = ExpectedValues( expected["arrival,"] = ExpectedValues(
@ -240,20 +241,18 @@ TEST(TestDataLog, VerifyMultipleTables) {
// Verify table 3 // Verify table 3
{ {
FILE* table = fopen("table3.txt", "r"); FILE* table = fopen("table_3.txt", "r");
ASSERT_FALSE(table == NULL); ASSERT_FALSE(table == NULL);
ExpectedValuesMap expected; ExpectedValuesMap expected;
expected["arrival,"] = ExpectedValues( expected["arrival,"] = ExpectedValues(
std::vector<std::string>(string_arrival, std::vector<std::string>(string_arrival,
string_arrival + string_arrival +
sizeof(string_arrival) kNumberOfRows),
/ sizeof(std::string)),
1); 1);
expected["timestamp,"] = ExpectedValues( expected["timestamp,"] = ExpectedValues(
std::vector<std::string>(string_timestamp, std::vector<std::string>(string_timestamp,
string_timestamp + string_timestamp +
sizeof(string_timestamp) / kNumberOfRows),
sizeof(std::string)),
1); 1);
ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0); ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
fclose(table); fclose(table);
@ -261,14 +260,13 @@ TEST(TestDataLog, VerifyMultipleTables) {
// Verify table 4 // Verify table 4
{ {
FILE* table = fopen("table4.txt", "r"); FILE* table = fopen("table_4.txt", "r");
ASSERT_FALSE(table == NULL); ASSERT_FALSE(table == NULL);
ExpectedValuesMap expected; ExpectedValuesMap expected;
expected["size,"] = ExpectedValues( expected["size,"] = ExpectedValues(
std::vector<std::string>(string_size, std::vector<std::string>(string_size,
string_size + string_size +
sizeof(string_size) kNumberOfRows),
/ sizeof(std::string)),
1); 1);
ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0); ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
fclose(table); fclose(table);