Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 : : /*
3 : : * Copyright 2010 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 <stdio.h>
19 : : #include <stdlib.h>
20 : : #include <string.h>
21 : :
22 : : #include "docio.h"
23 : : #include "wal.h"
24 : : #include "fdb_internal.h"
25 : : #ifdef _DOC_COMP
26 : : #include "snappy-c.h"
27 : : #endif
28 : :
29 : : #include "memleak.h"
30 : :
31 : 607 : void docio_init(struct docio_handle *handle,
32 : : struct filemgr *file,
33 : : bool compress_document_body)
34 : : {
35 : 607 : handle->file = file;
36 : 607 : handle->curblock = BLK_NOT_FOUND;
37 : 607 : handle->curpos = 0;
38 : 607 : handle->lastbid = BLK_NOT_FOUND;
39 : 607 : handle->compress_document_body = compress_document_body;
40 : 607 : malloc_align(handle->readbuffer, FDB_SECTOR_SIZE, file->blocksize);
41 : 607 : }
42 : :
43 : 604 : void docio_free(struct docio_handle *handle)
44 : : {
45 : 604 : free_align(handle->readbuffer);
46 : 604 : }
47 : :
48 : : #ifdef __CRC32
49 : : #define _add_blk_marker(file, bid, blocksize, marker, log_callback) \
50 : : filemgr_write_offset((file), (bid), (blocksize), BLK_MARKER_SIZE, (marker), (log_callback))
51 : : #else
52 : : #define _add_blk_marker(file, bid, blocksize, marker, log_callback) \
53 : : FDB_RESULT_SUCCESS
54 : : #endif
55 : :
56 : 4467328 : bid_t docio_append_doc_raw(struct docio_handle *handle, uint64_t size, void *buf)
57 : : {
58 : : uint32_t offset;
59 : : uint8_t marker[BLK_MARKER_SIZE];
60 : 4467328 : size_t blocksize = handle->file->blocksize;
61 : 4467328 : size_t real_blocksize = blocksize;
62 : 4467328 : err_log_callback *log_callback = handle->log_callback;
63 : : #ifdef __CRC32
64 : 4467328 : blocksize -= BLK_MARKER_SIZE;
65 : 4467328 : memset(marker, BLK_MARKER_DOC, BLK_MARKER_SIZE);
66 : : #endif
67 : :
68 [ + + ]: 4467328 : if (handle->curblock == BLK_NOT_FOUND) {
69 : : // allocate new block
70 : 372 : handle->curblock = filemgr_alloc(handle->file, log_callback);
71 : 372 : handle->curpos = 0;
72 : : }
73 [ + + ]: 4467328 : if (!filemgr_is_writable(handle->file, handle->curblock)) {
74 : : // allocate new block
75 : 13626 : handle->curblock = filemgr_alloc(handle->file, log_callback);
76 : 13626 : handle->curpos = 0;
77 : : }
78 : :
79 [ + + ]: 4467328 : if (size <= blocksize - handle->curpos) {
80 : : // simply append to current block
81 : 4245565 : offset = handle->curpos;
82 [ - + ]: 4245565 : if (_add_blk_marker(handle->file, handle->curblock, blocksize, marker,
83 : : log_callback) != FDB_RESULT_SUCCESS) {
84 : 0 : return BLK_NOT_FOUND;
85 : : }
86 [ - + ]: 4245565 : if (filemgr_write_offset(handle->file, handle->curblock, offset, size,
87 : 4245565 : buf, log_callback) != FDB_RESULT_SUCCESS) {
88 : 0 : return BLK_NOT_FOUND;
89 : : }
90 : 4245565 : handle->curpos += size;
91 : :
92 : 4245565 : return handle->curblock * real_blocksize + offset;
93 : :
94 : : }else{
95 : : // not simply fitted into current block
96 : : bid_t begin, end, i, startpos;
97 : 221763 : uint32_t nblock = size / blocksize;
98 : 221763 : uint32_t remain = size % blocksize;
99 : 221763 : uint64_t remainsize = size;
100 : :
101 : : #ifdef DOCIO_BLOCK_ALIGN
102 : : offset = blocksize - handle->curpos;
103 : : if (remain <= blocksize - handle->curpos &&
104 : : filemgr_alloc_multiple_cond(handle->file, handle->curblock+1,
105 : : nblock + ((remain>offset)?1:0), &begin, &end,
106 : : log_callback) == handle->curblock+1) {
107 : :
108 : : // start from current block
109 : : assert(begin == handle->curblock + 1);
110 : :
111 : : if (_add_blk_marker(handle->file, handle->curblock, blocksize,
112 : : marker, log_callback) != FDB_RESULT_SUCCESS) {
113 : : return BLK_NOT_FOUND;
114 : : }
115 : : if (offset > 0) {
116 : : if (filemgr_write_offset(handle->file, handle->curblock,
117 : : handle->curpos, offset, buf,
118 : : log_callback) != FDB_RESULT_SUCCESS) {
119 : : return BLK_NOT_FOUND;
120 : : }
121 : : }
122 : : remainsize -= offset;
123 : :
124 : : startpos = handle->curblock * real_blocksize + handle->curpos;
125 : : } else {
126 : : // next block to be allocated is not continuous .. allocate new multiple blocks
127 : : filemgr_alloc_multiple(handle->file, nblock+((remain>0)?1:0),
128 : : &begin, &end, log_callback);
129 : : offset = 0;
130 : :
131 : : startpos = begin * real_blocksize;
132 : : }
133 : :
134 : : #else
135 : : // simple append mode .. always append at the end of file
136 : 221763 : offset = blocksize - handle->curpos;
137 [ + + ]: 221763 : if (filemgr_alloc_multiple_cond(handle->file, handle->curblock+1,
138 : : nblock + ((remain>offset)?1:0), &begin, &end,
139 [ + - ]: 221763 : log_callback) == handle->curblock+1) {
140 : : // start from current block
141 [ - + ]: 218613 : assert(begin == handle->curblock + 1);
142 : :
143 [ + + ]: 218613 : if (_add_blk_marker(handle->file, handle->curblock, blocksize,
144 : : marker, log_callback) != FDB_RESULT_SUCCESS) {
145 : 1958 : return BLK_NOT_FOUND;
146 : : }
147 [ + + ]: 216655 : if (offset > 0) {
148 [ + + ]: 215169 : if (filemgr_write_offset(handle->file, handle->curblock,
149 : : handle->curpos, offset, buf,
150 : 215169 : log_callback) != FDB_RESULT_SUCCESS) {
151 : 1 : return BLK_NOT_FOUND;
152 : : }
153 : : }
154 : 216654 : remainsize -= offset;
155 : :
156 : 216654 : startpos = handle->curblock * real_blocksize + handle->curpos;
157 : : } else {
158 : : // next block to be allocated is not continuous .. allocate new multiple blocks
159 : : filemgr_alloc_multiple(handle->file, nblock+((remain>0)?1:0),
160 [ + - ]: 3150 : &begin, &end, log_callback);
161 : 3150 : offset = 0;
162 : :
163 : 3150 : startpos = begin * real_blocksize;
164 : : }
165 : :
166 : : #endif
167 : :
168 [ + + ]: 437650 : for (i=begin; i<=end; ++i) {
169 : 219805 : handle->curblock = i;
170 [ + + ]: 219805 : if (remainsize >= blocksize) {
171 : : // write entire block
172 [ - + ]: 1 : if (_add_blk_marker(handle->file, i, blocksize, marker,
173 : : log_callback) != FDB_RESULT_SUCCESS) {
174 : 0 : return BLK_NOT_FOUND;
175 : : }
176 [ - + ]: 1 : if (filemgr_write_offset(handle->file, i, 0, blocksize,
177 : 1 : (uint8_t *)buf + offset,
178 : 1 : log_callback) != FDB_RESULT_SUCCESS) {
179 : 0 : return BLK_NOT_FOUND;
180 : : }
181 : 1 : offset += blocksize;
182 : 1 : remainsize -= blocksize;
183 : 1 : handle->curpos = blocksize;
184 : :
185 : : } else {
186 : : // write rest of document
187 [ - + ]: 219804 : assert(i==end);
188 [ + + ]: 219804 : if (_add_blk_marker(handle->file, i, blocksize, marker,
189 : : log_callback) != FDB_RESULT_SUCCESS) {
190 : 1959 : return BLK_NOT_FOUND;
191 : : }
192 [ - + ]: 217845 : if (filemgr_write_offset(handle->file, i, 0, remainsize,
193 : 217845 : (uint8_t *)buf + offset,
194 : 217845 : log_callback) != FDB_RESULT_SUCCESS) {
195 : 0 : return BLK_NOT_FOUND;
196 : : }
197 : 217845 : offset += remainsize;
198 : 217845 : handle->curpos = remainsize;
199 : : }
200 : : }
201 : :
202 : 4467328 : return startpos;
203 : : }
204 : :
205 : : return 0;
206 : : }
207 : :
208 : : #ifdef __ENDIAN_SAFE
209 : 4467327 : INLINE struct docio_length _docio_length_encode(struct docio_length length)
210 : : {
211 : : struct docio_length ret;
212 : 4467327 : ret = length;
213 : 4467327 : ret.keylen = _endian_encode(length.keylen);
214 : 4467327 : ret.metalen = _endian_encode(length.metalen);
215 : 4467327 : ret.bodylen = _endian_encode(length.bodylen);
216 : 4467327 : ret.bodylen_ondisk = _endian_encode(length.bodylen_ondisk);
217 : 4467327 : return ret;
218 : : }
219 : 6518633 : INLINE struct docio_length _docio_length_decode(struct docio_length length)
220 : : {
221 : : struct docio_length ret;
222 : 6518633 : ret = length;
223 : 6518633 : ret.keylen = _endian_decode(length.keylen);
224 : 6518633 : ret.metalen = _endian_decode(length.metalen);
225 : 6518633 : ret.bodylen = _endian_decode(length.bodylen);
226 : 6518633 : ret.bodylen_ondisk = _endian_decode(length.bodylen_ondisk);
227 : 6518633 : return ret;
228 : : }
229 : : #else
230 : : #define _docio_length_encode(a)
231 : : #define _docio_length_decode(a)
232 : : #endif
233 : :
234 : 10987849 : INLINE uint8_t _docio_length_checksum(struct docio_length length)
235 : : {
236 : : return (uint8_t)(
237 : 10987849 : chksum(&length,
238 : : sizeof(keylen_t) + sizeof(uint16_t) + sizeof(uint32_t)*2)
239 : 10990475 : & 0xff);
240 : : }
241 : :
242 : 4346698 : INLINE bid_t _docio_append_doc(struct docio_handle *handle, struct docio_object *doc)
243 : : {
244 : : size_t _len;
245 : 4346698 : uint32_t offset = 0;
246 : : uint32_t crc;
247 : : uint64_t docsize;
248 : : void *buf;
249 : : bid_t ret_offset;
250 : : fdb_seqnum_t _seqnum;
251 : : timestamp_t _timestamp;
252 : : struct docio_length length, _length;
253 : 4346698 : err_log_callback *log_callback = handle->log_callback;
254 : :
255 : 4346698 : length = doc->length;
256 : 4346698 : length.bodylen_ondisk = length.bodylen;
257 : :
258 : : #ifdef _DOC_COMP
259 : : int ret;
260 : : void *compbuf;
261 : : uint32_t compbuf_len;
262 [ + + ][ + + ]: 4346698 : if (doc->length.bodylen > 0 && handle->compress_document_body) {
263 : 26 : compbuf_len = snappy_max_compressed_length(length.bodylen);
264 : 26 : compbuf = (void *)malloc(compbuf_len);
265 : :
266 : 26 : _len = compbuf_len;
267 : 26 : ret = snappy_compress((char*)doc->body, length.bodylen, (char*)compbuf, &_len);
268 [ - + ]: 26 : if (ret < 0) {
269 : : fdb_log(log_callback, FDB_RESULT_COMPRESSION_FAIL,
270 : : "Error in compressing the doc body of key '%s'",
271 : 0 : (char *) doc->key);
272 : : // we use BLK_NOT_FOUND for error code of appending instead of 0
273 : : // because document can be written at the byte offset 0
274 : 0 : return BLK_NOT_FOUND;
275 : : }
276 : :
277 : 26 : length.bodylen_ondisk = compbuf_len = _len;
278 : 26 : length.flag |= DOCIO_COMPRESSED;
279 : :
280 : 26 : docsize = sizeof(struct docio_length) + length.keylen + length.metalen;
281 : 26 : docsize += compbuf_len;
282 : : } else {
283 : 4346672 : docsize = sizeof(struct docio_length) + length.keylen + length.metalen + length.bodylen;
284 : : }
285 : : #else
286 : : docsize = sizeof(struct docio_length) + length.keylen + length.metalen + length.bodylen;
287 : : #endif
288 : 4346698 : docsize += sizeof(timestamp_t);
289 : :
290 : 4346698 : docsize += sizeof(fdb_seqnum_t);
291 : :
292 : : #ifdef __CRC32
293 : 4346698 : docsize += sizeof(crc);
294 : : #endif
295 : :
296 : 4346698 : doc->length = length;
297 : 4346698 : buf = (void *)malloc(docsize);
298 : :
299 : 4346698 : _length = _docio_length_encode(length);
300 : :
301 : : // calculate checksum of LENGTH using crc
302 : 4346697 : _length.checksum = _docio_length_checksum(_length);
303 : :
304 : 4346697 : memcpy((uint8_t *)buf + offset, &_length, sizeof(struct docio_length));
305 : 4346697 : offset += sizeof(struct docio_length);
306 : :
307 : : // copy key
308 : 4346697 : memcpy((uint8_t *)buf + offset, doc->key, length.keylen);
309 : 4346697 : offset += length.keylen;
310 : :
311 : : // copy timestamp
312 : 4346697 : _timestamp = _endian_encode(doc->timestamp);
313 : 4346697 : memcpy((uint8_t*)buf + offset, &_timestamp, sizeof(_timestamp));
314 : 4346697 : offset += sizeof(_timestamp);
315 : :
316 : : // copy seqeunce number (optional)
317 : 4346697 : _seqnum = _endian_encode(doc->seqnum);
318 : 4346697 : memcpy((uint8_t *)buf + offset, &_seqnum, sizeof(fdb_seqnum_t));
319 : 4346697 : offset += sizeof(fdb_seqnum_t);
320 : :
321 : : // copy metadata (optional)
322 [ + + ]: 4346697 : if (length.metalen > 0) {
323 : 4299515 : memcpy((uint8_t *)buf + offset, doc->meta, length.metalen);
324 : 4299515 : offset += length.metalen;
325 : : }
326 : :
327 : : // copy body (optional)
328 [ + + ]: 4346697 : if (length.bodylen > 0) {
329 : : #ifdef _DOC_COMP
330 [ + + ]: 4343763 : if (length.flag & DOCIO_COMPRESSED) {
331 : : // compressed body
332 : 26 : memcpy((uint8_t*)buf + offset, compbuf, compbuf_len);
333 : 26 : offset += compbuf_len;
334 : 26 : free(compbuf);
335 : : } else {
336 : 4343737 : memcpy((uint8_t *)buf + offset, doc->body, length.bodylen);
337 : 4343737 : offset += length.bodylen;
338 : : }
339 : : #else
340 : : memcpy((uint8_t *)buf + offset, doc->body, length.bodylen);
341 : : offset += length.bodylen;
342 : : #endif
343 : : }
344 : :
345 : : #ifdef __CRC32
346 : 4346697 : crc = chksum(buf, docsize - sizeof(crc));
347 : 4346698 : memcpy((uint8_t *)buf + offset, &crc, sizeof(crc));
348 : : #endif
349 : :
350 : 4346698 : ret_offset = docio_append_doc_raw(handle, docsize, buf);
351 : 4346697 : free(buf);
352 : :
353 : 4346697 : return ret_offset;
354 : : }
355 : :
356 : 120630 : bid_t docio_append_commit_mark(struct docio_handle *handle, uint64_t doc_offset)
357 : : {
358 : 120630 : uint32_t offset = 0;
359 : : uint64_t docsize;
360 : : uint64_t _doc_offset;
361 : : void *buf;
362 : : bid_t ret_offset;
363 : : struct docio_length length, _length;
364 : :
365 : 120630 : memset(&length, 0, sizeof(struct docio_length));
366 : 120630 : length.flag = DOCIO_TXN_COMMITTED;
367 : :
368 : 120630 : docsize = sizeof(struct docio_length) + sizeof(doc_offset);
369 : 120630 : buf = (void *)malloc(docsize);
370 : :
371 : 120630 : _length = _docio_length_encode(length);
372 : :
373 : : // calculate checksum of LENGTH using crc
374 : 120630 : _length.checksum = _docio_length_checksum(_length);
375 : :
376 : 120630 : memcpy((uint8_t *)buf + offset, &_length, sizeof(struct docio_length));
377 : 120630 : offset += sizeof(struct docio_length);
378 : :
379 : : // copy doc_offset
380 : 120630 : _doc_offset = _endian_encode(doc_offset);
381 : 120630 : memcpy((uint8_t *)buf + offset, &_doc_offset, sizeof(_doc_offset));
382 : :
383 : 120630 : ret_offset = docio_append_doc_raw(handle, docsize, buf);
384 : 120630 : free(buf);
385 : :
386 : 120630 : return ret_offset;
387 : : }
388 : :
389 : 45571 : bid_t docio_append_doc_compact(struct docio_handle *handle, struct docio_object *doc,
390 : : uint8_t deleted, uint8_t txn_enabled)
391 : : {
392 : 45571 : doc->length.flag = DOCIO_COMPACT;
393 [ - + ]: 45571 : if (deleted) {
394 : 0 : doc->length.flag |= DOCIO_DELETED;
395 : : }
396 [ + + ]: 45571 : if (txn_enabled) {
397 : 22200 : doc->length.flag |= DOCIO_TXN_DIRTY;
398 : : }
399 : 45571 : return _docio_append_doc(handle, doc);
400 : : }
401 : :
402 : 4287248 : bid_t docio_append_doc(struct docio_handle *handle, struct docio_object *doc,
403 : : uint8_t deleted, uint8_t txn_enabled)
404 : : {
405 : 4287248 : doc->length.flag = DOCIO_NORMAL;
406 [ + + ]: 4287248 : if (deleted) {
407 : 731 : doc->length.flag |= DOCIO_DELETED;
408 : : }
409 [ + + ]: 4287248 : if (txn_enabled) {
410 : 99099 : doc->length.flag |= DOCIO_TXN_DIRTY;
411 : : }
412 : 4287248 : return _docio_append_doc(handle, doc);
413 : : }
414 : :
415 : 13878 : bid_t docio_append_doc_system(struct docio_handle *handle, struct docio_object *doc)
416 : : {
417 : 13878 : doc->length.flag = DOCIO_NORMAL | DOCIO_SYSTEM;
418 : 13878 : return _docio_append_doc(handle, doc);
419 : : }
420 : :
421 : 31922761 : INLINE fdb_status _docio_read_through_buffer(struct docio_handle *handle,
422 : : bid_t bid,
423 : : err_log_callback *log_callback)
424 : : {
425 : 31922761 : fdb_status status = FDB_RESULT_SUCCESS;
426 : : // to reduce the overhead from memcpy the same block
427 [ + + ]: 31922761 : if (handle->lastbid != bid) {
428 : : status = filemgr_read(handle->file, bid, handle->readbuffer,
429 : 3260177 : log_callback);
430 [ + + ]: 3269127 : if (status != FDB_RESULT_SUCCESS) {
431 : 1 : return status;
432 : : }
433 : :
434 [ + + ]: 3269126 : if (filemgr_is_writable(handle->file, bid)) {
435 : : // this block can be modified later .. must be re-read
436 : 1658862 : handle->lastbid = BLK_NOT_FOUND;
437 : : }else{
438 : 1607062 : handle->lastbid = bid;
439 : : }
440 : : }
441 : :
442 : 31928509 : return status;
443 : : }
444 : :
445 : 6510147 : uint64_t _docio_read_length(struct docio_handle *handle,
446 : : uint64_t offset,
447 : : struct docio_length *length,
448 : : err_log_callback *log_callback)
449 : : {
450 : 6510147 : size_t blocksize = handle->file->blocksize;
451 : 6510147 : size_t real_blocksize = blocksize;
452 : : #ifdef __CRC32
453 : 6510147 : blocksize -= BLK_MARKER_SIZE;
454 : : #endif
455 : :
456 [ - + ]: 6510147 : if (filemgr_get_pos(handle->file) < (offset + sizeof(struct docio_length))) {
457 : 0 : return offset;
458 : : }
459 : :
460 : 6528499 : bid_t bid = offset / real_blocksize;
461 : 6528499 : uint32_t pos = offset % real_blocksize;
462 : 6528499 : void *buf = handle->readbuffer;
463 : : uint32_t restsize;
464 : :
465 : 6528499 : restsize = blocksize - pos;
466 : : // read length structure
467 : 6528499 : _docio_read_through_buffer(handle, bid, log_callback);
468 : :
469 [ + + ]: 6526237 : if (restsize >= sizeof(struct docio_length)) {
470 : 6499127 : memcpy(length, (uint8_t *)buf + pos, sizeof(struct docio_length));
471 : 6499127 : pos += sizeof(struct docio_length);
472 : :
473 : : }else{
474 : 27110 : memcpy(length, (uint8_t *)buf + pos, restsize);
475 : : // read additional block
476 : 27110 : bid++;
477 : 27110 : _docio_read_through_buffer(handle, bid, log_callback);
478 : : // memcpy rest of data
479 : 27110 : memcpy((uint8_t *)length + restsize, buf, sizeof(struct docio_length) - restsize);
480 : 27110 : pos = sizeof(struct docio_length) - restsize;
481 : : }
482 : :
483 : 6526237 : return bid * real_blocksize + pos;
484 : : }
485 : :
486 : 25386273 : uint64_t _docio_read_doc_component(struct docio_handle *handle,
487 : : uint64_t offset,
488 : : uint32_t len,
489 : : void *buf_out,
490 : : err_log_callback *log_callback)
491 : : {
492 : : uint32_t rest_len;
493 : 25386273 : size_t blocksize = handle->file->blocksize;
494 : 25386273 : size_t real_blocksize = blocksize;
495 : : #ifdef __CRC32
496 : 25386273 : blocksize -= BLK_MARKER_SIZE;
497 : : #endif
498 : :
499 : 25386273 : bid_t bid = offset / real_blocksize;
500 : 25386273 : uint32_t pos = offset % real_blocksize;
501 : : //uint8_t buf[handle->file->blocksize];
502 : 25386273 : void *buf = handle->readbuffer;
503 : : uint32_t restsize;
504 : :
505 : 25386273 : rest_len = len;
506 : :
507 [ + + ]: 50797898 : while(rest_len > 0) {
508 : 25415992 : _docio_read_through_buffer(handle, bid, log_callback);
509 : 25411620 : restsize = blocksize - pos;
510 : :
511 [ + + ]: 25411620 : if (restsize >= rest_len) {
512 : 25207155 : memcpy((uint8_t *)buf_out + (len - rest_len), (uint8_t *)buf + pos, rest_len);
513 : 25207155 : pos += rest_len;
514 : 25207155 : rest_len = 0;
515 : : }else{
516 : 204465 : memcpy((uint8_t *)buf_out + (len - rest_len), (uint8_t *)buf + pos, restsize);
517 : 204465 : bid++;
518 : 204465 : pos = 0;
519 : 204465 : rest_len -= restsize;
520 : :
521 [ + - - + ]: 408935 : if (rest_len > 0 &&
[ - + ]
522 : 204465 : bid >= filemgr_get_pos(handle->file) / handle->file->blocksize) {
523 : : // no more data in the file .. the file is corrupted
524 : : fdb_log(log_callback, FDB_RESULT_FILE_CORRUPTION,
525 : : "Fatal error!!! Database file '%s' is corrupted.",
526 : 0 : handle->file->filename);
527 : : // TODO: Need to return a better error code.
528 : 0 : return 0;
529 : : }
530 : : }
531 : : }
532 : :
533 : 25381906 : return bid * real_blocksize + pos;
534 : : }
535 : :
536 : : #ifdef _DOC_COMP
537 : :
538 : 41 : uint64_t _docio_read_doc_component_comp(struct docio_handle *handle,
539 : : uint64_t offset,
540 : : uint32_t len,
541 : : uint32_t comp_len,
542 : : void *buf_out,
543 : : void *comp_data_out,
544 : : err_log_callback *log_callback)
545 : : {
546 : : int ret;
547 : : size_t uncomp_size;
548 : : uint64_t _offset;
549 : :
550 : : _offset = _docio_read_doc_component(handle, offset,
551 : 41 : comp_len, comp_data_out, log_callback);
552 [ - + ]: 41 : if (_offset == 0) {
553 : 0 : return 0;
554 : : }
555 : :
556 : 41 : uncomp_size = len;
557 : : ret = snappy_uncompress((char*)comp_data_out, comp_len,
558 : 41 : (char*)buf_out, &uncomp_size);
559 [ - + ]: 41 : if (ret < 0) return 0;
560 : :
561 [ - + ]: 41 : assert(uncomp_size == len);
562 : 41 : return _offset;
563 : : }
564 : :
565 : : #endif
566 : :
567 : : // return length.keylen = 0 if failure
568 : 500468 : struct docio_length docio_read_doc_length(struct docio_handle *handle, uint64_t offset)
569 : : {
570 : : uint8_t checksum;
571 : : uint64_t _offset;
572 : : struct docio_length length, _length;
573 : 500468 : err_log_callback *log_callback = handle->log_callback;
574 : :
575 : 500468 : _offset = _docio_read_length(handle, offset, &_length, log_callback);
576 [ - + ]: 500468 : if (_offset == offset) {
577 : 0 : length.keylen = 0;
578 : 0 : return length;
579 : : }
580 : :
581 : : // checksum check
582 : 500468 : checksum = _docio_length_checksum(_length);
583 [ - + ]: 500468 : if (checksum != _length.checksum) {
584 : : fdb_log(log_callback, FDB_RESULT_CHECKSUM_ERROR,
585 : : "doc_length checksum mismatch error in a database file '%s'",
586 : 0 : handle->file->filename);
587 : 0 : length.keylen = 0;
588 : 0 : return length;
589 : : }
590 : :
591 : 500468 : length = _docio_length_decode(_length);
592 [ + - ][ - + ]: 500468 : if (length.keylen == 0 || length.keylen > FDB_MAX_KEYLEN_INTERNAL) {
593 : 0 : length.keylen = 0;
594 : 0 : return length;
595 : : }
596 : :
597 : : // document size check
598 [ - + ]: 500468 : if (offset + sizeof(struct docio_length) +
599 : : length.keylen + length.metalen + length.bodylen_ondisk >
600 : 500468 : filemgr_get_pos(handle->file)) {
601 : : fdb_log(log_callback, FDB_RESULT_FILE_CORRUPTION,
602 : : "Fatal error!!! Database file '%s' is corrupted.",
603 : 0 : handle->file->filename);
604 : 0 : length.keylen = 0;
605 : 0 : return length;
606 : : }
607 : :
608 : 500468 : return length;
609 : : }
610 : :
611 : : // return length.keylen = 0 if failure
612 : 1900544 : void docio_read_doc_key(struct docio_handle *handle, uint64_t offset,
613 : : keylen_t *keylen, void *keybuf)
614 : : {
615 : : uint8_t checksum;
616 : : uint64_t _offset;
617 : : struct docio_length length, _length;
618 : 1900544 : err_log_callback *log_callback = handle->log_callback;
619 : :
620 : 1900544 : _offset = _docio_read_length(handle, offset, &_length, log_callback);
621 [ - + ]: 1902566 : if (_offset == offset) {
622 : 0 : *keylen = 0;
623 : 0 : return;
624 : : }
625 : :
626 : : // checksum check
627 : 1902566 : checksum = _docio_length_checksum(_length);
628 [ + + ]: 1901982 : if (checksum != _length.checksum) {
629 : : fdb_log(log_callback, FDB_RESULT_CHECKSUM_ERROR,
630 : : "doc_length checksum mismatch error in a database file '%s'",
631 : 1 : handle->file->filename);
632 : 1 : *keylen = 0;
633 : 1 : return;
634 : : }
635 : :
636 : 1901981 : length = _docio_length_decode(_length);
637 [ + + ][ - + ]: 1902569 : if (length.keylen == 0 || length.keylen > FDB_MAX_KEYLEN_INTERNAL) {
638 : 0 : *keylen = 0;
639 : 0 : return;
640 : : }
641 : :
642 : : // document size check
643 [ - + ]: 1902662 : if (offset + sizeof(struct docio_length) +
644 : : length.keylen + length.metalen + length.bodylen_ondisk >
645 : 1902569 : filemgr_get_pos(handle->file)) {
646 : : fdb_log(log_callback, FDB_RESULT_FILE_CORRUPTION,
647 : : "Fatal error!!! Database file '%s' is corrupted.",
648 : 0 : handle->file->filename);
649 : 0 : *keylen = 0;
650 : 0 : return;
651 : : }
652 : :
653 : 1902662 : _docio_read_doc_component(handle, _offset, length.keylen, keybuf, log_callback);
654 : 1901887 : *keylen = length.keylen;
655 : : }
656 : :
657 : 3546982 : void free_docio_object(struct docio_object *doc, uint8_t key_alloc,
658 : : uint8_t meta_alloc, uint8_t body_alloc) {
659 [ - + ]: 3546982 : if (!doc) {
660 : 3546982 : return;
661 : : }
662 : :
663 [ + + ]: 3546982 : if (key_alloc) {
664 : 223 : free(doc->key);
665 : 223 : doc->key = NULL;
666 : : }
667 [ + + ]: 3546982 : if (meta_alloc) {
668 : 110151 : free(doc->meta);
669 : 110151 : doc->meta = NULL;
670 : : }
671 [ + + ]: 3546982 : if (body_alloc) {
672 : 1444 : free(doc->body);
673 : 1444 : doc->body = NULL;
674 : : }
675 : : }
676 : :
677 : 573092 : uint64_t docio_read_doc_key_meta(struct docio_handle *handle, uint64_t offset,
678 : : struct docio_object *doc)
679 : : {
680 : : uint8_t checksum;
681 : : uint64_t _offset;
682 : 573092 : int key_alloc = 0;
683 : 573092 : int meta_alloc = 0;
684 : : fdb_seqnum_t _seqnum;
685 : : timestamp_t _timestamp;
686 : : struct docio_length _length;
687 : 573092 : err_log_callback *log_callback = handle->log_callback;
688 : :
689 : 573092 : _offset = _docio_read_length(handle, offset, &_length, log_callback);
690 [ - + ]: 575272 : if (_offset == offset) {
691 : 0 : return offset;
692 : : }
693 : :
694 : : // checksum check
695 : 575272 : checksum = _docio_length_checksum(_length);
696 [ - + ]: 574880 : if (checksum != _length.checksum) {
697 : : fdb_log(log_callback, FDB_RESULT_CHECKSUM_ERROR,
698 : : "doc_length checksum mismatch error in a database file '%s'",
699 : 0 : handle->file->filename);
700 : 0 : return offset;
701 : : }
702 : :
703 : 574880 : doc->length = _docio_length_decode(_length);
704 [ + + ][ # + ]: 575161 : if (doc->length.keylen == 0 || doc->length.keylen > FDB_MAX_KEYLEN_INTERNAL) {
705 : 0 : return offset;
706 : : }
707 : :
708 : : // document size check
709 [ - + ]: 575327 : if (offset + sizeof(struct docio_length) +
710 : : doc->length.keylen + doc->length.metalen + doc->length.bodylen_ondisk >
711 : 575161 : filemgr_get_pos(handle->file)) {
712 : : fdb_log(log_callback, FDB_RESULT_FILE_CORRUPTION,
713 : : "Fatal error!!! Database file '%s' is corrupted.",
714 : 0 : handle->file->filename);
715 : 0 : return offset;
716 : : }
717 : :
718 [ + + ]: 575327 : if (doc->key == NULL) {
719 : 391471 : doc->key = (void *)malloc(doc->length.keylen);
720 : 391471 : key_alloc = 1;
721 : : }
722 [ + + ]: 575327 : if (doc->meta == NULL) {
723 : 575253 : doc->meta = (void *)malloc(doc->length.metalen);
724 : 575253 : meta_alloc = 1;
725 : : }
726 : :
727 [ + + ][ # + ]: 575327 : assert(doc->key && doc->meta);
728 : :
729 : : _offset = _docio_read_doc_component(handle, _offset, doc->length.keylen,
730 : 575261 : doc->key, log_callback);
731 [ - + ]: 574704 : if (_offset == 0) {
732 : 0 : free_docio_object(doc, key_alloc, meta_alloc, 0);
733 : 0 : return offset;
734 : : }
735 : :
736 : : // read timestamp
737 : : _offset = _docio_read_doc_component(handle, _offset,
738 : : sizeof(timestamp_t),
739 : 574704 : &_timestamp, log_callback);
740 [ - + ]: 573992 : if (_offset == 0) {
741 : 0 : free_docio_object(doc, key_alloc, meta_alloc, 0);
742 : 0 : return offset;
743 : : }
744 : 573992 : doc->timestamp = _endian_decode(_timestamp);
745 : :
746 : : // copy sequence number (optional)
747 : : _offset = _docio_read_doc_component(handle, _offset, sizeof(fdb_seqnum_t),
748 : 573992 : (void *)&_seqnum, log_callback);
749 [ - + ]: 573362 : if (_offset == 0) {
750 : 0 : free_docio_object(doc, key_alloc, meta_alloc, 0);
751 : 0 : return offset;
752 : : }
753 : 573362 : doc->seqnum = _endian_decode(_seqnum);
754 : :
755 : : _offset = _docio_read_doc_component(handle, _offset, doc->length.metalen,
756 : 573362 : doc->meta, log_callback);
757 [ - + ]: 573954 : if (_offset == 0) {
758 : 0 : free_docio_object(doc, key_alloc, meta_alloc, 0);
759 : 0 : return offset;
760 : : }
761 : :
762 : 573954 : return _offset;
763 : : }
764 : :
765 : 3546001 : uint64_t docio_read_doc(struct docio_handle *handle, uint64_t offset,
766 : : struct docio_object *doc)
767 : : {
768 : : uint8_t checksum;
769 : : uint64_t _offset;
770 : 3546001 : int key_alloc = 0;
771 : 3546001 : int meta_alloc = 0;
772 : 3546001 : int body_alloc = 0;
773 : : fdb_seqnum_t _seqnum;
774 : : timestamp_t _timestamp;
775 : 3546001 : void *comp_body = NULL;
776 : : struct docio_length _length;
777 : 3546001 : err_log_callback *log_callback = handle->log_callback;
778 : :
779 : 3546001 : _offset = _docio_read_length(handle, offset, &_length, log_callback);
780 [ - + ]: 3549769 : if (_offset == offset) {
781 : 0 : return offset;
782 : : }
783 : :
784 : : // checksum check
785 : 3549769 : checksum = _docio_length_checksum(_length);
786 [ + + ]: 3549324 : if (checksum != _length.checksum) {
787 : : fdb_log(log_callback, FDB_RESULT_CHECKSUM_ERROR,
788 : : "doc_length checksum mismatch error in a database file '%s'",
789 : 572 : handle->file->filename);
790 : 572 : return offset;
791 : : }
792 : :
793 : 3548752 : doc->length = _docio_length_decode(_length);
794 [ + + ]: 3549508 : if (doc->length.flag & DOCIO_TXN_COMMITTED) {
795 : : // transaction commit mark
796 : : // read the corresponding doc offset
797 : : uint64_t doc_offset;
798 : : _offset = _docio_read_doc_component(handle, _offset,
799 : : sizeof(doc_offset), &doc_offset,
800 : 1210 : log_callback);
801 [ - + ]: 1210 : if (_offset == 0) {
802 : 0 : free_docio_object(doc, key_alloc, meta_alloc, body_alloc);
803 : 0 : return offset;
804 : : }
805 : 1210 : doc->doc_offset = _endian_decode(doc_offset);
806 : 1210 : return _offset;
807 : : }
808 : :
809 [ + + ][ - + ]: 3548298 : if (doc->length.keylen == 0 || doc->length.keylen > FDB_MAX_KEYLEN_INTERNAL) {
810 : 0 : return offset;
811 : : }
812 : :
813 : : // document size check
814 [ - + ]: 3548314 : if (offset + sizeof(struct docio_length) +
815 : : doc->length.keylen + doc->length.metalen + doc->length.bodylen_ondisk >
816 : 3548298 : filemgr_get_pos(handle->file)) {
817 : : fdb_log(log_callback, FDB_RESULT_FILE_CORRUPTION,
818 : : "Fatal error!!! Database file '%s' is corrupted.",
819 : 0 : handle->file->filename);
820 : 0 : return offset;
821 : : }
822 : :
823 [ + + ]: 3548314 : if (doc->key == NULL) {
824 : 2130639 : doc->key = (void *)malloc(doc->length.keylen);
825 : 2130639 : key_alloc = 1;
826 : : }
827 [ + + ]: 3548314 : if (doc->meta == NULL) {
828 : 3548443 : doc->meta = (void *)malloc(doc->length.metalen);
829 : 3548443 : meta_alloc = 1;
830 : : }
831 [ + + ]: 3548314 : if (doc->body == NULL) {
832 : 3548381 : doc->body = (void *)malloc(doc->length.bodylen);
833 : 3548381 : body_alloc = 1;
834 : : }
835 : :
836 [ + - ][ + + ]: 3548314 : assert(doc->key && doc->meta && doc->body);
[ - + ]
837 : :
838 : : _offset = _docio_read_doc_component(handle, _offset,
839 : : doc->length.keylen,
840 : : doc->key,
841 : 3548079 : log_callback);
842 [ - + ]: 3547218 : if (_offset == 0) {
843 : 0 : free_docio_object(doc, key_alloc, meta_alloc, body_alloc);
844 : 0 : return offset;
845 : : }
846 : :
847 : : // read timestamp
848 : : _offset = _docio_read_doc_component(handle, _offset,
849 : : sizeof(timestamp_t),
850 : : &_timestamp,
851 : 3547218 : log_callback);
852 [ - + ]: 3546825 : if (_offset == 0) {
853 : 0 : free_docio_object(doc, key_alloc, meta_alloc, body_alloc);
854 : 0 : return offset;
855 : : }
856 : 3546825 : doc->timestamp = _endian_decode(_timestamp);
857 : :
858 : : // copy seqeunce number (optional)
859 : : _offset = _docio_read_doc_component(handle, _offset,
860 : : sizeof(fdb_seqnum_t),
861 : : (void *)&_seqnum,
862 : 3546825 : log_callback);
863 [ - + ]: 3545915 : if (_offset == 0) {
864 : 0 : free_docio_object(doc, key_alloc, meta_alloc, body_alloc);
865 : 0 : return offset;
866 : : }
867 : 3545915 : doc->seqnum = _endian_decode(_seqnum);
868 : :
869 : : _offset = _docio_read_doc_component(handle, _offset, doc->length.metalen,
870 : 3545915 : doc->meta, log_callback);
871 [ - + ]: 3546095 : if (_offset == 0) {
872 : 0 : free_docio_object(doc, key_alloc, meta_alloc, body_alloc);
873 : 0 : return offset;
874 : : }
875 : :
876 : : #ifdef _DOC_COMP
877 [ + + ]: 3546095 : if (doc->length.flag & DOCIO_COMPRESSED) {
878 : 41 : comp_body = (void*)malloc(doc->length.bodylen_ondisk);
879 : : _offset = _docio_read_doc_component_comp(handle, _offset, doc->length.bodylen,
880 : : doc->length.bodylen_ondisk, doc->body,
881 : 41 : comp_body, log_callback);
882 [ - + ]: 41 : if (_offset == 0) {
883 [ # # ]: 0 : if (comp_body) {
884 : 0 : free(comp_body);
885 : : }
886 : 0 : free_docio_object(doc, key_alloc, meta_alloc, body_alloc);
887 : 0 : return offset;
888 : : }
889 : : } else {
890 : : _offset = _docio_read_doc_component(handle, _offset, doc->length.bodylen,
891 : 3546054 : doc->body, log_callback);
892 [ - + ]: 3545565 : if (_offset == 0) {
893 : 0 : free_docio_object(doc, key_alloc, meta_alloc, body_alloc);
894 : 0 : return offset;
895 : : }
896 : : }
897 : : #else
898 : : _offset = _docio_read_doc_component(handle, _offset, doc->length.bodylen,
899 : : doc->body, log_callback);
900 : : if (_offset == 0) {
901 : : if (comp_body) {
902 : : free(comp_body);
903 : : }
904 : : free_docio_object(doc, key_alloc, meta_alloc, body_alloc);
905 : : return offset;
906 : : }
907 : : #endif
908 : :
909 : : #ifdef __CRC32
910 : : uint32_t crc_file, crc;
911 : : _offset = _docio_read_doc_component(handle, _offset, sizeof(crc_file),
912 : 3545606 : (void *)&crc_file, log_callback);
913 [ - + ]: 3547029 : if (_offset == 0) {
914 [ # # ]: 0 : if (comp_body) {
915 : 0 : free(comp_body);
916 : : }
917 : 0 : free_docio_object(doc, key_alloc, meta_alloc, body_alloc);
918 : 0 : return offset;
919 : : }
920 : :
921 : 3547029 : crc = chksum((void *)&_length, sizeof(_length));
922 : 3546776 : crc = chksum_scd(doc->key, doc->length.keylen, crc);
923 : 3547792 : crc = chksum_scd((void *)&_timestamp, sizeof(timestamp_t), crc);
924 : 3547239 : crc = chksum_scd((void *)&_seqnum, sizeof(fdb_seqnum_t), crc);
925 : 3547042 : crc = chksum_scd(doc->meta, doc->length.metalen, crc);
926 [ + + ]: 3546929 : if (doc->length.flag & DOCIO_COMPRESSED) {
927 : 41 : crc = chksum_scd(comp_body, doc->length.bodylen_ondisk, crc);
928 [ + + ]: 1621 : if (comp_body) {
929 : 41 : free(comp_body);
930 : : }
931 : : } else {
932 : 3546888 : crc = chksum_scd(doc->body, doc->length.bodylen, crc);
933 : : }
934 [ - + ]: 3547159 : if (crc != crc_file) {
935 : : fdb_log(log_callback, FDB_RESULT_CHECKSUM_ERROR,
936 : : "doc_body checksum mismatch error in a database file '%s'",
937 : 0 : handle->file->filename);
938 : 0 : free_docio_object(doc, key_alloc, meta_alloc, body_alloc);
939 : 0 : return offset;
940 : : }
941 : : #endif
942 : :
943 [ + + ][ + + ]: 3547159 : uint8_t free_meta = meta_alloc && !doc->length.metalen;
944 [ + + ][ + + ]: 3547159 : uint8_t free_body = body_alloc && !doc->length.bodylen;
945 : 3547159 : free_docio_object(doc, 0, free_meta, free_body);
946 : :
947 : 3548057 : return _offset;
948 : : }
949 : :
950 : 915 : int docio_check_buffer(struct docio_handle *handle, bid_t bid)
951 : : {
952 : : uint8_t marker[BLK_MARKER_SIZE];
953 : 915 : err_log_callback *log_callback = handle->log_callback;
954 : 915 : _docio_read_through_buffer(handle, bid, log_callback);
955 : : marker[0] = *(((uint8_t *)handle->readbuffer)
956 : 915 : + handle->file->blocksize - BLK_MARKER_SIZE);
957 : 915 : return (marker[0] == BLK_MARKER_DOC);
958 : : }
959 : :
960 : 0 : int docio_check_compact_doc(struct docio_handle *handle,
961 : : struct docio_object *doc)
962 : : {
963 [ # # ]: 0 : if (doc->length.flag & DOCIO_COMPACT) return 1;
964 : 0 : else return 0;
965 : : }
966 : :
967 : :
|