leveldb-ruby 0.7 → 0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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_
|