leveldb-ruby 0.7 → 0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -1
- data/leveldb/Makefile +70 -29
- data/leveldb/build_detect_platform +74 -0
- data/leveldb/db/builder.cc +2 -4
- data/leveldb/db/builder.h +4 -6
- data/leveldb/db/c.cc +471 -0
- data/leveldb/db/corruption_test.cc +21 -16
- data/leveldb/db/db_bench.cc +400 -200
- data/leveldb/db/db_impl.cc +276 -131
- data/leveldb/db/db_impl.h +22 -10
- data/leveldb/db/db_iter.cc +2 -1
- data/leveldb/db/db_test.cc +391 -43
- data/leveldb/db/dbformat.cc +31 -0
- data/leveldb/db/dbformat.h +51 -1
- data/leveldb/db/filename.h +1 -1
- data/leveldb/db/log_format.h +1 -1
- data/leveldb/db/log_reader.cc +16 -11
- data/leveldb/db/memtable.cc +37 -0
- data/leveldb/db/memtable.h +6 -0
- data/leveldb/db/repair.cc +17 -14
- data/leveldb/db/skiplist_test.cc +2 -2
- data/leveldb/db/version_edit.cc +7 -9
- data/leveldb/db/version_edit.h +2 -1
- data/leveldb/db/version_set.cc +416 -104
- data/leveldb/db/version_set.h +78 -14
- data/leveldb/db/version_set_test.cc +179 -0
- data/leveldb/db/write_batch_internal.h +2 -0
- data/leveldb/include/leveldb/c.h +246 -0
- data/leveldb/include/leveldb/db.h +14 -2
- data/leveldb/include/leveldb/env.h +31 -10
- data/leveldb/include/leveldb/options.h +7 -18
- data/leveldb/include/leveldb/slice.h +2 -2
- data/leveldb/include/leveldb/status.h +1 -1
- data/leveldb/port/atomic_pointer.h +144 -0
- data/leveldb/port/port.h +0 -2
- data/leveldb/port/port_android.h +7 -1
- data/leveldb/port/port_example.h +11 -1
- data/leveldb/port/port_posix.h +56 -38
- data/leveldb/table/format.cc +12 -8
- data/leveldb/table/table_test.cc +16 -7
- data/leveldb/util/cache.cc +173 -100
- data/leveldb/util/cache_test.cc +28 -11
- data/leveldb/util/coding.h +4 -4
- data/leveldb/util/comparator.cc +1 -0
- data/leveldb/util/env.cc +10 -5
- data/leveldb/util/env_posix.cc +48 -87
- data/leveldb/util/histogram.cc +11 -0
- data/leveldb/util/histogram.h +1 -0
- data/leveldb/util/posix_logger.h +98 -0
- data/leveldb/util/testharness.cc +12 -0
- data/leveldb/util/testharness.h +10 -1
- data/lib/leveldb.rb +11 -3
- metadata +41 -22
data/leveldb/util/cache_test.cc
CHANGED
@@ -32,7 +32,7 @@ class CacheTest {
|
|
32
32
|
current_->deleted_values_.push_back(DecodeValue(v));
|
33
33
|
}
|
34
34
|
|
35
|
-
static const int kCacheSize =
|
35
|
+
static const int kCacheSize = 1000;
|
36
36
|
std::vector<int> deleted_keys_;
|
37
37
|
std::vector<int> deleted_values_;
|
38
38
|
Cache* cache_;
|
@@ -137,23 +137,40 @@ TEST(CacheTest, EvictionPolicy) {
|
|
137
137
|
Insert(200, 201);
|
138
138
|
|
139
139
|
// Frequently used entry must be kept around
|
140
|
-
for (int i = 0; i < kCacheSize; i++) {
|
140
|
+
for (int i = 0; i < kCacheSize + 100; i++) {
|
141
141
|
Insert(1000+i, 2000+i);
|
142
142
|
ASSERT_EQ(2000+i, Lookup(1000+i));
|
143
143
|
ASSERT_EQ(101, Lookup(100));
|
144
144
|
}
|
145
145
|
ASSERT_EQ(101, Lookup(100));
|
146
|
-
ASSERT_EQ(
|
147
|
-
ASSERT_EQ(200, deleted_keys_[0]);
|
148
|
-
ASSERT_EQ(201, deleted_values_[0]);
|
146
|
+
ASSERT_EQ(-1, Lookup(200));
|
149
147
|
}
|
150
148
|
|
151
|
-
TEST(CacheTest,
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
149
|
+
TEST(CacheTest, HeavyEntries) {
|
150
|
+
// Add a bunch of light and heavy entries and then count the combined
|
151
|
+
// size of items still in the cache, which must be approximately the
|
152
|
+
// same as the total capacity.
|
153
|
+
const int kLight = 1;
|
154
|
+
const int kHeavy = 10;
|
155
|
+
int added = 0;
|
156
|
+
int index = 0;
|
157
|
+
while (added < 2*kCacheSize) {
|
158
|
+
const int weight = (index & 1) ? kLight : kHeavy;
|
159
|
+
Insert(index, 1000+index, weight);
|
160
|
+
added += weight;
|
161
|
+
index++;
|
162
|
+
}
|
163
|
+
|
164
|
+
int cached_weight = 0;
|
165
|
+
for (int i = 0; i < index; i++) {
|
166
|
+
const int weight = (i & 1 ? kLight : kHeavy);
|
167
|
+
int r = Lookup(i);
|
168
|
+
if (r >= 0) {
|
169
|
+
cached_weight += weight;
|
170
|
+
ASSERT_EQ(1000+i, r);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
ASSERT_LE(cached_weight, kCacheSize + kCacheSize/10);
|
157
174
|
}
|
158
175
|
|
159
176
|
TEST(CacheTest, NewId) {
|
data/leveldb/util/coding.h
CHANGED
@@ -62,10 +62,10 @@ inline uint32_t DecodeFixed32(const char* ptr) {
|
|
62
62
|
memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load
|
63
63
|
return result;
|
64
64
|
} else {
|
65
|
-
return ((static_cast<uint32_t>(ptr[0]))
|
66
|
-
|
67
|
-
|
68
|
-
|
65
|
+
return ((static_cast<uint32_t>(static_cast<unsigned char>(ptr[0])))
|
66
|
+
| (static_cast<uint32_t>(static_cast<unsigned char>(ptr[1])) << 8)
|
67
|
+
| (static_cast<uint32_t>(static_cast<unsigned char>(ptr[2])) << 16)
|
68
|
+
| (static_cast<uint32_t>(static_cast<unsigned char>(ptr[3])) << 24));
|
69
69
|
}
|
70
70
|
}
|
71
71
|
|
data/leveldb/util/comparator.cc
CHANGED
data/leveldb/util/env.cc
CHANGED
@@ -18,14 +18,19 @@ RandomAccessFile::~RandomAccessFile() {
|
|
18
18
|
WritableFile::~WritableFile() {
|
19
19
|
}
|
20
20
|
|
21
|
+
Logger::~Logger() {
|
22
|
+
}
|
23
|
+
|
21
24
|
FileLock::~FileLock() {
|
22
25
|
}
|
23
26
|
|
24
|
-
void Log(
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
void Log(Logger* info_log, const char* format, ...) {
|
28
|
+
if (info_log != NULL) {
|
29
|
+
va_list ap;
|
30
|
+
va_start(ap, format);
|
31
|
+
info_log->Logv(format, ap);
|
32
|
+
va_end(ap);
|
33
|
+
}
|
29
34
|
}
|
30
35
|
|
31
36
|
Status WriteStringToFile(Env* env, const Slice& data,
|
data/leveldb/util/env_posix.cc
CHANGED
@@ -23,11 +23,16 @@
|
|
23
23
|
#include "leveldb/slice.h"
|
24
24
|
#include "port/port.h"
|
25
25
|
#include "util/logging.h"
|
26
|
+
#include "util/posix_logger.h"
|
26
27
|
|
27
28
|
namespace leveldb {
|
28
29
|
|
29
30
|
namespace {
|
30
31
|
|
32
|
+
static Status IOError(const std::string& context, int err_number) {
|
33
|
+
return Status::IOError(context, strerror(err_number));
|
34
|
+
}
|
35
|
+
|
31
36
|
class PosixSequentialFile: public SequentialFile {
|
32
37
|
private:
|
33
38
|
std::string filename_;
|
@@ -47,7 +52,7 @@ class PosixSequentialFile: public SequentialFile {
|
|
47
52
|
// We leave status as ok if we hit the end of the file
|
48
53
|
} else {
|
49
54
|
// A partial read with an error: return a non-ok status
|
50
|
-
s =
|
55
|
+
s = IOError(filename_, errno);
|
51
56
|
}
|
52
57
|
}
|
53
58
|
return s;
|
@@ -55,7 +60,7 @@ class PosixSequentialFile: public SequentialFile {
|
|
55
60
|
|
56
61
|
virtual Status Skip(uint64_t n) {
|
57
62
|
if (fseek(file_, n, SEEK_CUR)) {
|
58
|
-
return
|
63
|
+
return IOError(filename_, errno);
|
59
64
|
}
|
60
65
|
return Status::OK();
|
61
66
|
}
|
@@ -78,7 +83,7 @@ class PosixRandomAccessFile: public RandomAccessFile {
|
|
78
83
|
*result = Slice(scratch, (r < 0) ? 0 : r);
|
79
84
|
if (r < 0) {
|
80
85
|
// An error: return a non-ok status
|
81
|
-
s =
|
86
|
+
s = IOError(filename_, errno);
|
82
87
|
}
|
83
88
|
return s;
|
84
89
|
}
|
@@ -114,13 +119,16 @@ class PosixMmapFile : public WritableFile {
|
|
114
119
|
return s;
|
115
120
|
}
|
116
121
|
|
117
|
-
|
122
|
+
bool UnmapCurrentRegion() {
|
123
|
+
bool result = true;
|
118
124
|
if (base_ != NULL) {
|
119
125
|
if (last_sync_ < limit_) {
|
120
126
|
// Defer syncing this data until next Sync() call, if any
|
121
127
|
pending_sync_ = true;
|
122
128
|
}
|
123
|
-
munmap(base_, limit_ - base_)
|
129
|
+
if (munmap(base_, limit_ - base_) != 0) {
|
130
|
+
result = false;
|
131
|
+
}
|
124
132
|
file_offset_ += limit_ - base_;
|
125
133
|
base_ = NULL;
|
126
134
|
limit_ = NULL;
|
@@ -132,6 +140,7 @@ class PosixMmapFile : public WritableFile {
|
|
132
140
|
map_size_ *= 2;
|
133
141
|
}
|
134
142
|
}
|
143
|
+
return result;
|
135
144
|
}
|
136
145
|
|
137
146
|
bool MapNewRegion() {
|
@@ -181,8 +190,10 @@ class PosixMmapFile : public WritableFile {
|
|
181
190
|
assert(dst_ <= limit_);
|
182
191
|
size_t avail = limit_ - dst_;
|
183
192
|
if (avail == 0) {
|
184
|
-
UnmapCurrentRegion()
|
185
|
-
|
193
|
+
if (!UnmapCurrentRegion() ||
|
194
|
+
!MapNewRegion()) {
|
195
|
+
return IOError(filename_, errno);
|
196
|
+
}
|
186
197
|
}
|
187
198
|
|
188
199
|
size_t n = (left <= avail) ? left : avail;
|
@@ -197,17 +208,18 @@ class PosixMmapFile : public WritableFile {
|
|
197
208
|
virtual Status Close() {
|
198
209
|
Status s;
|
199
210
|
size_t unused = limit_ - dst_;
|
200
|
-
UnmapCurrentRegion()
|
201
|
-
|
211
|
+
if (!UnmapCurrentRegion()) {
|
212
|
+
s = IOError(filename_, errno);
|
213
|
+
} else if (unused > 0) {
|
202
214
|
// Trim the extra space at the end of the file
|
203
215
|
if (ftruncate(fd_, file_offset_ - unused) < 0) {
|
204
|
-
s =
|
216
|
+
s = IOError(filename_, errno);
|
205
217
|
}
|
206
218
|
}
|
207
219
|
|
208
220
|
if (close(fd_) < 0) {
|
209
221
|
if (s.ok()) {
|
210
|
-
s =
|
222
|
+
s = IOError(filename_, errno);
|
211
223
|
}
|
212
224
|
}
|
213
225
|
|
@@ -228,7 +240,7 @@ class PosixMmapFile : public WritableFile {
|
|
228
240
|
// Some unmapped data was not synced
|
229
241
|
pending_sync_ = false;
|
230
242
|
if (fdatasync(fd_) < 0) {
|
231
|
-
s =
|
243
|
+
s = IOError(filename_, errno);
|
232
244
|
}
|
233
245
|
}
|
234
246
|
|
@@ -239,7 +251,7 @@ class PosixMmapFile : public WritableFile {
|
|
239
251
|
size_t p2 = TruncateToPageBoundary(dst_ - base_ - 1);
|
240
252
|
last_sync_ = dst_;
|
241
253
|
if (msync(base_ + p1, p2 - p1 + page_size_, MS_SYNC) < 0) {
|
242
|
-
s =
|
254
|
+
s = IOError(filename_, errno);
|
243
255
|
}
|
244
256
|
}
|
245
257
|
|
@@ -276,7 +288,7 @@ class PosixEnv : public Env {
|
|
276
288
|
FILE* f = fopen(fname.c_str(), "r");
|
277
289
|
if (f == NULL) {
|
278
290
|
*result = NULL;
|
279
|
-
return
|
291
|
+
return IOError(fname, errno);
|
280
292
|
} else {
|
281
293
|
*result = new PosixSequentialFile(fname, f);
|
282
294
|
return Status::OK();
|
@@ -288,7 +300,7 @@ class PosixEnv : public Env {
|
|
288
300
|
int fd = open(fname.c_str(), O_RDONLY);
|
289
301
|
if (fd < 0) {
|
290
302
|
*result = NULL;
|
291
|
-
return
|
303
|
+
return IOError(fname, errno);
|
292
304
|
}
|
293
305
|
*result = new PosixRandomAccessFile(fname, fd);
|
294
306
|
return Status::OK();
|
@@ -300,7 +312,7 @@ class PosixEnv : public Env {
|
|
300
312
|
const int fd = open(fname.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0644);
|
301
313
|
if (fd < 0) {
|
302
314
|
*result = NULL;
|
303
|
-
s =
|
315
|
+
s = IOError(fname, errno);
|
304
316
|
} else {
|
305
317
|
*result = new PosixMmapFile(fname, fd, page_size_);
|
306
318
|
}
|
@@ -316,7 +328,7 @@ class PosixEnv : public Env {
|
|
316
328
|
result->clear();
|
317
329
|
DIR* d = opendir(dir.c_str());
|
318
330
|
if (d == NULL) {
|
319
|
-
return
|
331
|
+
return IOError(dir, errno);
|
320
332
|
}
|
321
333
|
struct dirent* entry;
|
322
334
|
while ((entry = readdir(d)) != NULL) {
|
@@ -329,7 +341,7 @@ class PosixEnv : public Env {
|
|
329
341
|
virtual Status DeleteFile(const std::string& fname) {
|
330
342
|
Status result;
|
331
343
|
if (unlink(fname.c_str()) != 0) {
|
332
|
-
result =
|
344
|
+
result = IOError(fname, errno);
|
333
345
|
}
|
334
346
|
return result;
|
335
347
|
};
|
@@ -337,7 +349,7 @@ class PosixEnv : public Env {
|
|
337
349
|
virtual Status CreateDir(const std::string& name) {
|
338
350
|
Status result;
|
339
351
|
if (mkdir(name.c_str(), 0755) != 0) {
|
340
|
-
result =
|
352
|
+
result = IOError(name, errno);
|
341
353
|
}
|
342
354
|
return result;
|
343
355
|
};
|
@@ -345,7 +357,7 @@ class PosixEnv : public Env {
|
|
345
357
|
virtual Status DeleteDir(const std::string& name) {
|
346
358
|
Status result;
|
347
359
|
if (rmdir(name.c_str()) != 0) {
|
348
|
-
result =
|
360
|
+
result = IOError(name, errno);
|
349
361
|
}
|
350
362
|
return result;
|
351
363
|
};
|
@@ -355,7 +367,7 @@ class PosixEnv : public Env {
|
|
355
367
|
struct stat sbuf;
|
356
368
|
if (stat(fname.c_str(), &sbuf) != 0) {
|
357
369
|
*size = 0;
|
358
|
-
s =
|
370
|
+
s = IOError(fname, errno);
|
359
371
|
} else {
|
360
372
|
*size = sbuf.st_size;
|
361
373
|
}
|
@@ -365,7 +377,7 @@ class PosixEnv : public Env {
|
|
365
377
|
virtual Status RenameFile(const std::string& src, const std::string& target) {
|
366
378
|
Status result;
|
367
379
|
if (rename(src.c_str(), target.c_str()) != 0) {
|
368
|
-
result =
|
380
|
+
result = IOError(src, errno);
|
369
381
|
}
|
370
382
|
return result;
|
371
383
|
}
|
@@ -375,9 +387,9 @@ class PosixEnv : public Env {
|
|
375
387
|
Status result;
|
376
388
|
int fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644);
|
377
389
|
if (fd < 0) {
|
378
|
-
result =
|
390
|
+
result = IOError(fname, errno);
|
379
391
|
} else if (LockOrUnlock(fd, true) == -1) {
|
380
|
-
result =
|
392
|
+
result = IOError("lock " + fname, errno);
|
381
393
|
close(fd);
|
382
394
|
} else {
|
383
395
|
PosixFileLock* my_lock = new PosixFileLock;
|
@@ -391,7 +403,7 @@ class PosixEnv : public Env {
|
|
391
403
|
PosixFileLock* my_lock = reinterpret_cast<PosixFileLock*>(lock);
|
392
404
|
Status result;
|
393
405
|
if (LockOrUnlock(my_lock->fd_, false) == -1) {
|
394
|
-
result =
|
406
|
+
result = IOError("unlock", errno);
|
395
407
|
}
|
396
408
|
close(my_lock->fd_);
|
397
409
|
delete my_lock;
|
@@ -416,72 +428,21 @@ class PosixEnv : public Env {
|
|
416
428
|
return Status::OK();
|
417
429
|
}
|
418
430
|
|
419
|
-
|
431
|
+
static uint64_t gettid() {
|
420
432
|
pthread_t tid = pthread_self();
|
421
433
|
uint64_t thread_id = 0;
|
422
434
|
memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid)));
|
435
|
+
return thread_id;
|
436
|
+
}
|
423
437
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
base = buffer;
|
433
|
-
} else {
|
434
|
-
bufsize = 30000;
|
435
|
-
base = new char[bufsize];
|
436
|
-
}
|
437
|
-
char* p = base;
|
438
|
-
char* limit = base + bufsize;
|
439
|
-
|
440
|
-
struct timeval now_tv;
|
441
|
-
gettimeofday(&now_tv, NULL);
|
442
|
-
const time_t seconds = now_tv.tv_sec;
|
443
|
-
struct tm t;
|
444
|
-
localtime_r(&seconds, &t);
|
445
|
-
p += snprintf(p, limit - p,
|
446
|
-
"%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
|
447
|
-
t.tm_year + 1900,
|
448
|
-
t.tm_mon + 1,
|
449
|
-
t.tm_mday,
|
450
|
-
t.tm_hour,
|
451
|
-
t.tm_min,
|
452
|
-
t.tm_sec,
|
453
|
-
static_cast<int>(now_tv.tv_usec),
|
454
|
-
static_cast<long long unsigned int>(thread_id));
|
455
|
-
|
456
|
-
// Print the message
|
457
|
-
if (p < limit) {
|
458
|
-
va_list backup_ap;
|
459
|
-
va_copy(backup_ap, ap);
|
460
|
-
p += vsnprintf(p, limit - p, format, backup_ap);
|
461
|
-
va_end(backup_ap);
|
462
|
-
}
|
463
|
-
|
464
|
-
// Truncate to available space if necessary
|
465
|
-
if (p >= limit) {
|
466
|
-
if (iter == 0) {
|
467
|
-
continue; // Try again with larger buffer
|
468
|
-
} else {
|
469
|
-
p = limit - 1;
|
470
|
-
}
|
471
|
-
}
|
472
|
-
|
473
|
-
// Add newline if necessary
|
474
|
-
if (p == base || p[-1] != '\n') {
|
475
|
-
*p++ = '\n';
|
476
|
-
}
|
477
|
-
|
478
|
-
assert(p <= limit);
|
479
|
-
info_log->Append(Slice(base, p - base));
|
480
|
-
info_log->Flush();
|
481
|
-
if (base != buffer) {
|
482
|
-
delete[] base;
|
483
|
-
}
|
484
|
-
break;
|
438
|
+
virtual Status NewLogger(const std::string& fname, Logger** result) {
|
439
|
+
FILE* f = fopen(fname.c_str(), "w");
|
440
|
+
if (f == NULL) {
|
441
|
+
*result = NULL;
|
442
|
+
return IOError(fname, errno);
|
443
|
+
} else {
|
444
|
+
*result = new PosixLogger(f, &PosixEnv::gettid);
|
445
|
+
return Status::OK();
|
485
446
|
}
|
486
447
|
}
|
487
448
|
|
data/leveldb/util/histogram.cc
CHANGED
@@ -55,6 +55,17 @@ void Histogram::Add(double value) {
|
|
55
55
|
sum_squares_ += (value * value);
|
56
56
|
}
|
57
57
|
|
58
|
+
void Histogram::Merge(const Histogram& other) {
|
59
|
+
if (other.min_ < min_) min_ = other.min_;
|
60
|
+
if (other.max_ > max_) max_ = other.max_;
|
61
|
+
num_ += other.num_;
|
62
|
+
sum_ += other.sum_;
|
63
|
+
sum_squares_ += other.sum_squares_;
|
64
|
+
for (int b = 0; b < kNumBuckets; b++) {
|
65
|
+
buckets_[b] += other.buckets_[b];
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
58
69
|
double Histogram::Median() const {
|
59
70
|
return Percentile(50.0);
|
60
71
|
}
|
data/leveldb/util/histogram.h
CHANGED
@@ -0,0 +1,98 @@
|
|
1
|
+
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
4
|
+
//
|
5
|
+
// Logger implementation that can be shared by all environments
|
6
|
+
// where enough posix functionality is available.
|
7
|
+
|
8
|
+
#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_
|
9
|
+
#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_
|
10
|
+
|
11
|
+
#include <algorithm>
|
12
|
+
#include <stdio.h>
|
13
|
+
#include <sys/time.h>
|
14
|
+
#include <time.h>
|
15
|
+
#include "leveldb/env.h"
|
16
|
+
|
17
|
+
namespace leveldb {
|
18
|
+
|
19
|
+
class PosixLogger : public Logger {
|
20
|
+
private:
|
21
|
+
FILE* file_;
|
22
|
+
uint64_t (*gettid_)(); // Return the thread id for the current thread
|
23
|
+
public:
|
24
|
+
PosixLogger(FILE* f, uint64_t (*gettid)()) : file_(f), gettid_(gettid) { }
|
25
|
+
virtual ~PosixLogger() {
|
26
|
+
fclose(file_);
|
27
|
+
}
|
28
|
+
virtual void Logv(const char* format, va_list ap) {
|
29
|
+
const uint64_t thread_id = (*gettid_)();
|
30
|
+
|
31
|
+
// We try twice: the first time with a fixed-size stack allocated buffer,
|
32
|
+
// and the second time with a much larger dynamically allocated buffer.
|
33
|
+
char buffer[500];
|
34
|
+
for (int iter = 0; iter < 2; iter++) {
|
35
|
+
char* base;
|
36
|
+
int bufsize;
|
37
|
+
if (iter == 0) {
|
38
|
+
bufsize = sizeof(buffer);
|
39
|
+
base = buffer;
|
40
|
+
} else {
|
41
|
+
bufsize = 30000;
|
42
|
+
base = new char[bufsize];
|
43
|
+
}
|
44
|
+
char* p = base;
|
45
|
+
char* limit = base + bufsize;
|
46
|
+
|
47
|
+
struct timeval now_tv;
|
48
|
+
gettimeofday(&now_tv, NULL);
|
49
|
+
const time_t seconds = now_tv.tv_sec;
|
50
|
+
struct tm t;
|
51
|
+
localtime_r(&seconds, &t);
|
52
|
+
p += snprintf(p, limit - p,
|
53
|
+
"%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
|
54
|
+
t.tm_year + 1900,
|
55
|
+
t.tm_mon + 1,
|
56
|
+
t.tm_mday,
|
57
|
+
t.tm_hour,
|
58
|
+
t.tm_min,
|
59
|
+
t.tm_sec,
|
60
|
+
static_cast<int>(now_tv.tv_usec),
|
61
|
+
static_cast<long long unsigned int>(thread_id));
|
62
|
+
|
63
|
+
// Print the message
|
64
|
+
if (p < limit) {
|
65
|
+
va_list backup_ap;
|
66
|
+
va_copy(backup_ap, ap);
|
67
|
+
p += vsnprintf(p, limit - p, format, backup_ap);
|
68
|
+
va_end(backup_ap);
|
69
|
+
}
|
70
|
+
|
71
|
+
// Truncate to available space if necessary
|
72
|
+
if (p >= limit) {
|
73
|
+
if (iter == 0) {
|
74
|
+
continue; // Try again with larger buffer
|
75
|
+
} else {
|
76
|
+
p = limit - 1;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
// Add newline if necessary
|
81
|
+
if (p == base || p[-1] != '\n') {
|
82
|
+
*p++ = '\n';
|
83
|
+
}
|
84
|
+
|
85
|
+
assert(p <= limit);
|
86
|
+
fwrite(base, 1, p - base, file_);
|
87
|
+
fflush(file_);
|
88
|
+
if (base != buffer) {
|
89
|
+
delete[] base;
|
90
|
+
}
|
91
|
+
break;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
};
|
95
|
+
|
96
|
+
}
|
97
|
+
|
98
|
+
#endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_
|