1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2015 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 
18 #include "couchstoretest.h"
19 #include <libcouchstore/couch_db.h>
20 #include <src/internal.h>
21 
22 /**
23  * Callback function for latency info.
24  * This is a simple example how to get latency info.
25  */
couchstore_test_latency_callback(const char* stat_name, CouchLatencyHisto* latencies, const CouchLatencyMicroSecRep elapsed_time, void* ctx)26 int couchstore_test_latency_callback(const char* stat_name,
27                                      CouchLatencyHisto* latencies,
28                                      const CouchLatencyMicroSecRep elapsed_time,
29                                      void* ctx) {
30     (void)ctx;
31     size_t total = latencies->total();
32     std::cout << stat_name;
33     std::cout << ": " << total << " calls, ";
34     std::cout << "avg " << (elapsed_time / total);
35     std::cout << " us" << std::endl;
36     std::stringstream ss;
37     for (auto& itr_hist : *latencies) {
38         if (itr_hist->count()) {
39             ss << "  ";
40             ss << itr_hist->start() << " us";
41             ss << " -- ";
42             ss << itr_hist->end() << " us";
43             ss << ": ";
44             ss << itr_hist->count();
45             ss << std::endl;
46         }
47     }
48     std::cout << ss.str();
49     return 0;
50 }
51 
CouchstoreTest()52 CouchstoreTest::CouchstoreTest()
53     : CouchstoreTest("testfile.couch"){
54 }
55 
CouchstoreTest(const std::string& _filePath, const bool _display_latency_info)56 CouchstoreTest::CouchstoreTest(const std::string& _filePath,
57                                const bool _display_latency_info)
58     : db(nullptr),
59       filePath(_filePath),
60       displayLatencyInfo(_display_latency_info) {
61     couchstore_latency_collector_start();
62     remove(filePath.c_str());
63 }
64 
65 /**
66     Called after each test finishes.
67       - Closes db (if non-null)
68       - Removes testfile.couch
69 **/
~CouchstoreTest()70 CouchstoreTest::~CouchstoreTest() {
71     clean_up();
72     /* make sure os.c didn't accidentally call close(0): */
73 #ifndef WIN32
74     EXPECT_TRUE(lseek(0, 0, SEEK_CUR) >= 0 || errno != EBADF);
75 #endif
76 }
77 
clean_up()78 void CouchstoreTest::clean_up() {
79     if (db) {
80         couchstore_close_file(db);
81         couchstore_free_db(db);
82         db = nullptr;
83     }
84 
85     if (displayLatencyInfo) {
86         couchstore_latency_dump_options options;
87         couchstore_get_latency_info(couchstore_test_latency_callback,
88                                     options,
89                                     nullptr);
90     }
91     couchstore_latency_collector_stop();
92 
93     remove(filePath.c_str());
94 }
95 
CouchstoreInternalTest()96 CouchstoreInternalTest::CouchstoreInternalTest()
97         : CouchstoreTest("testfile_internal.couch"),
98           compactPath("testfile_internal.couch.compact"),
99           documents(Documents(0)),
100           ops(create_default_file_ops()) {
101     remove(compactPath.c_str());
102 }
103 
~CouchstoreInternalTest()104 CouchstoreInternalTest::~CouchstoreInternalTest() {
105     // Destruct db here instead of parent so that ops isn't destructed
106     // when we try to destruct the db.
107     clean_up();
108     remove(compactPath.c_str());
109 }
110 
open_db(couchstore_open_flags extra_flags)111 couchstore_error_t CouchstoreInternalTest::open_db(couchstore_open_flags extra_flags) {
112     return couchstore_open_db_ex(filePath.c_str(),
113                                  extra_flags | COUCHSTORE_OPEN_FLAG_UNBUFFERED,
114                                  &ops, &db);
115 }
116 
117 
open_db_and_populate(couchstore_open_flags extra_flags, size_t count)118 void CouchstoreInternalTest::open_db_and_populate(couchstore_open_flags extra_flags,
119                                                   size_t count) {
120     ASSERT_EQ(COUCHSTORE_SUCCESS, open_db(extra_flags));
121     documents = Documents(count);
122     documents.generateDocs();
123     ASSERT_EQ(COUCHSTORE_SUCCESS,
124               couchstore_save_documents(db, documents.getDocs(),
125                                         documents.getDocInfos(), count, 0));
126 
127 }
128 
create_local_doc(std::string& id, std::string& json)129 LocalDoc CouchstoreInternalTest::create_local_doc(std::string& id,
130                                                   std::string& json) {
131     LocalDoc doc;
132     doc.id.buf = &id[0];
133     doc.id.size = strlen(doc.id.buf);
134     doc.json.buf = &json[0];
135     doc.json.size = strlen(doc.json.buf);
136     doc.deleted = 0;
137     return doc;
138 }
139 
CouchstoreMTTest()140 CouchstoreMTTest::CouchstoreMTTest()
141     : CouchstoreMTTest("testfile_mt.couch") {
142 }
143 
CouchstoreMTTest(const std::string& _filePath)144 CouchstoreMTTest::CouchstoreMTTest(const std::string& _filePath)
145     : numThreads(std::get<1>(GetParam())),
146       dbs(numThreads),
147       filePath(_filePath) {
148 }
149 
TearDown()150 void CouchstoreMTTest::TearDown() {
151     for (size_t ii=0; ii<numThreads; ++ii) {
152         std::string actual_file_path = filePath + std::to_string(ii);
153         remove(actual_file_path.c_str());
154 
155         if (dbs[ii]) {
156             couchstore_close_file(dbs[ii]);
157             couchstore_free_db(dbs[ii]);
158             dbs[ii] = nullptr;
159         }
160     }
161 }
162 
163