typedef u32 tdb_len_t |
tdb_private.h の 43 行で定義されています。
typedef u32 tdb_off_t |
tdb_private.h の 44 行で定義されています。
int tdb_munmap | ( | struct tdb_context * | tdb | ) |
参照先 tdb_context::flags・tdb_context::map_ptr・tdb_context::map_size・tdb.
参照元 tdb_close()・tdb_expand()・tdb_oob()・tdb_open_ex()・tdb_reopen()・tdb_transaction_recover().
00187 { 00188 if (tdb->flags & TDB_INTERNAL) 00189 return 0; 00190 00191 #ifdef HAVE_MMAP 00192 if (tdb->map_ptr) { 00193 int ret = munmap(tdb->map_ptr, tdb->map_size); 00194 if (ret != 0) 00195 return ret; 00196 } 00197 #endif 00198 tdb->map_ptr = NULL; 00199 return 0; 00200 }
void tdb_mmap | ( | struct tdb_context * | tdb | ) |
参照先 errno・tdb_context::fd・tdb_context::flags・tdb_context::map_ptr・tdb_context::map_size・tdb_context::read_only・strerror()・tdb・TDB_DEBUG_WARNING.
参照元 tdb_expand()・tdb_oob()・tdb_open_ex()・tdb_reopen()・tdb_transaction_recover().
00203 { 00204 if (tdb->flags & TDB_INTERNAL) 00205 return; 00206 00207 #ifdef HAVE_MMAP 00208 if (!(tdb->flags & TDB_NOMMAP)) { 00209 tdb->map_ptr = mmap(NULL, tdb->map_size, 00210 PROT_READ|(tdb->read_only? 0:PROT_WRITE), 00211 MAP_SHARED|MAP_FILE, tdb->fd, 0); 00212 00213 /* 00214 * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!! 00215 */ 00216 00217 if (tdb->map_ptr == MAP_FAILED) { 00218 tdb->map_ptr = NULL; 00219 TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n", 00220 tdb->map_size, strerror(errno))); 00221 } 00222 } else { 00223 tdb->map_ptr = NULL; 00224 } 00225 #else 00226 tdb->map_ptr = NULL; 00227 #endif 00228 }
int tdb_lock | ( | struct tdb_context * | tdb, | |
int | list, | |||
int | ltype | |||
) |
参照先 tdb_lock_type::count・tdb_context::flags・tdb_context::global_lock・tdb_header::hash_size・tdb_context::header・tdb_lock_type::list・tdb_context::lockrecs・tdb_lock_type::ltype・tdb_context::num_lockrecs・tdb・TDB_DEBUG_ERROR・TDB_ERR_LOCK.
参照元 tdb_allocate()・tdb_append()・tdb_chainlock()・tdb_chainlock_read()・tdb_delete_hash()・tdb_dump_chain()・tdb_expand()・tdb_find_lock_hash()・tdb_free()・tdb_next_lock()・tdb_nextkey()・tdb_printfreelist()・tdb_purge_dead()・tdb_store()・tdb_validate_freelist().
00121 { 00122 struct tdb_lock_type *new_lck; 00123 int i; 00124 00125 /* a global lock allows us to avoid per chain locks */ 00126 if (tdb->global_lock.count && 00127 (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) { 00128 return 0; 00129 } 00130 00131 if (tdb->global_lock.count) { 00132 return TDB_ERRCODE(TDB_ERR_LOCK, -1); 00133 } 00134 00135 if (list < -1 || list >= (int)tdb->header.hash_size) { 00136 TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid list %d for ltype=%d\n", 00137 list, ltype)); 00138 return -1; 00139 } 00140 if (tdb->flags & TDB_NOLOCK) 00141 return 0; 00142 00143 for (i=0; i<tdb->num_lockrecs; i++) { 00144 if (tdb->lockrecs[i].list == list) { 00145 if (tdb->lockrecs[i].count == 0) { 00146 /* 00147 * Can't happen, see tdb_unlock(). It should 00148 * be an assert. 00149 */ 00150 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock: " 00151 "lck->count == 0 for list %d", list)); 00152 } 00153 /* 00154 * Just increment the in-memory struct, posix locks 00155 * don't stack. 00156 */ 00157 tdb->lockrecs[i].count++; 00158 return 0; 00159 } 00160 } 00161 00162 new_lck = (struct tdb_lock_type *)realloc( 00163 tdb->lockrecs, 00164 sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1)); 00165 if (new_lck == NULL) { 00166 errno = ENOMEM; 00167 return -1; 00168 } 00169 tdb->lockrecs = new_lck; 00170 00171 /* Since fcntl locks don't nest, we do a lock for the first one, 00172 and simply bump the count for future ones */ 00173 if (tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW, 00174 0, 1)) { 00175 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d " 00176 "ltype=%d (%s)\n", list, ltype, strerror(errno))); 00177 return -1; 00178 } 00179 00180 tdb->num_locks++; 00181 00182 tdb->lockrecs[tdb->num_lockrecs].list = list; 00183 tdb->lockrecs[tdb->num_lockrecs].count = 1; 00184 tdb->lockrecs[tdb->num_lockrecs].ltype = ltype; 00185 tdb->num_lockrecs += 1; 00186 00187 return 0; 00188 }
int tdb_unlock | ( | struct tdb_context * | tdb, | |
int | list, | |||
int | ltype | |||
) |
参照先 tdb_lock_type::count・tdb_context::flags・tdb_context::global_lock・tdb_header::hash_size・tdb_context::header・tdb_lock_type::list・tdb_context::lockrecs・tdb_lock_type::ltype・tdb_context::num_lockrecs・tdb・TDB_DEBUG_ERROR・TDB_ERR_LOCK.
参照元 tdb_allocate()・tdb_append()・tdb_chainunlock()・tdb_chainunlock_read()・tdb_delete_hash()・tdb_dump_chain()・tdb_exists_hash()・tdb_expand()・tdb_fetch()・tdb_find_lock_hash()・tdb_firstkey()・tdb_free()・tdb_next_lock()・tdb_nextkey()・tdb_parse_record()・tdb_printfreelist()・tdb_purge_dead()・tdb_store()・tdb_traverse_internal()・tdb_validate_freelist().
00194 { 00195 int ret = -1; 00196 int i; 00197 struct tdb_lock_type *lck = NULL; 00198 00199 /* a global lock allows us to avoid per chain locks */ 00200 if (tdb->global_lock.count && 00201 (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) { 00202 return 0; 00203 } 00204 00205 if (tdb->global_lock.count) { 00206 return TDB_ERRCODE(TDB_ERR_LOCK, -1); 00207 } 00208 00209 if (tdb->flags & TDB_NOLOCK) 00210 return 0; 00211 00212 /* Sanity checks */ 00213 if (list < -1 || list >= (int)tdb->header.hash_size) { 00214 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size)); 00215 return ret; 00216 } 00217 00218 for (i=0; i<tdb->num_lockrecs; i++) { 00219 if (tdb->lockrecs[i].list == list) { 00220 lck = &tdb->lockrecs[i]; 00221 break; 00222 } 00223 } 00224 00225 if ((lck == NULL) || (lck->count == 0)) { 00226 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n")); 00227 return -1; 00228 } 00229 00230 if (lck->count > 1) { 00231 lck->count--; 00232 return 0; 00233 } 00234 00235 /* 00236 * This lock has count==1 left, so we need to unlock it in the 00237 * kernel. We don't bother with decrementing the in-memory array 00238 * element, we're about to overwrite it with the last array element 00239 * anyway. 00240 */ 00241 00242 ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, 00243 F_SETLKW, 0, 1); 00244 tdb->num_locks--; 00245 00246 /* 00247 * Shrink the array by overwriting the element just unlocked with the 00248 * last array element. 00249 */ 00250 00251 if (tdb->num_lockrecs > 1) { 00252 *lck = tdb->lockrecs[tdb->num_lockrecs-1]; 00253 } 00254 tdb->num_lockrecs -= 1; 00255 00256 /* 00257 * We don't bother with realloc when the array shrinks, but if we have 00258 * a completely idle tdb we should get rid of the locked array. 00259 */ 00260 00261 if (tdb->num_lockrecs == 0) { 00262 SAFE_FREE(tdb->lockrecs); 00263 } 00264 00265 if (ret) 00266 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n")); 00267 return ret; 00268 }
int tdb_brlock | ( | struct tdb_context * | tdb, | |
tdb_off_t | offset, | |||
int | rw_type, | |||
int | lck_type, | |||
int | probe, | |||
size_t | len | |||
) |
参照先 tdb_context::ecode・errno・tdb_context::fd・tdb_context::flags・tdb_context::interrupt_sig_ptr・tdb_context::read_only・tdb・TDB_DEBUG_TRACE・TDB_ERR_LOCK・TDB_ERR_RDONLY・tdb_context::traverse_read.
参照元 tdb_brlock_upgrade()・tdb_increment_seqnum()・tdb_transaction_cancel()・tdb_transaction_commit()・tdb_transaction_start().
00046 { 00047 struct flock fl; 00048 int ret; 00049 00050 if (tdb->flags & TDB_NOLOCK) { 00051 return 0; 00052 } 00053 00054 if ((rw_type == F_WRLCK) && (tdb->read_only || tdb->traverse_read)) { 00055 tdb->ecode = TDB_ERR_RDONLY; 00056 return -1; 00057 } 00058 00059 fl.l_type = rw_type; 00060 fl.l_whence = SEEK_SET; 00061 fl.l_start = offset; 00062 fl.l_len = len; 00063 fl.l_pid = 0; 00064 00065 do { 00066 ret = fcntl(tdb->fd,lck_type,&fl); 00067 00068 /* Check for a sigalarm break. */ 00069 if (ret == -1 && errno == EINTR && 00070 tdb->interrupt_sig_ptr && 00071 *tdb->interrupt_sig_ptr) { 00072 break; 00073 } 00074 } while (ret == -1 && errno == EINTR); 00075 00076 if (ret == -1) { 00077 /* Generic lock error. errno set by fcntl. 00078 * EAGAIN is an expected return from non-blocking 00079 * locks. */ 00080 if (!probe && lck_type != F_SETLK) { 00081 /* Ensure error code is set for log fun to examine. */ 00082 tdb->ecode = TDB_ERR_LOCK; 00083 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n", 00084 tdb->fd, offset, rw_type, lck_type, (int)len)); 00085 } 00086 return TDB_ERRCODE(TDB_ERR_LOCK, -1); 00087 } 00088 return 0; 00089 }
int tdb_brlock_upgrade | ( | struct tdb_context * | tdb, | |
tdb_off_t | offset, | |||
size_t | len | |||
) |
参照先 errno・tdb・tdb_brlock()・TDB_DEBUG_TRACE.
00099 { 00100 int count = 1000; 00101 while (count--) { 00102 struct timeval tv; 00103 if (tdb_brlock(tdb, offset, F_WRLCK, F_SETLKW, 1, len) == 0) { 00104 return 0; 00105 } 00106 if (errno != EDEADLK) { 00107 break; 00108 } 00109 /* sleep for as short a time as we can - more portable than usleep() */ 00110 tv.tv_sec = 0; 00111 tv.tv_usec = 1; 00112 select(0, NULL, NULL, NULL, &tv); 00113 } 00114 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock_upgrade failed at offset %d\n", offset)); 00115 return -1; 00116 }
int tdb_write_lock_record | ( | struct tdb_context * | tdb, | |
tdb_off_t | off | |||
) |
参照先 tdb_context::methods・tdb_traverse_lock::next・tdb_traverse_lock::off・tdb・tdb_methods::tdb_brlock・tdb_context::travlocks.
参照元 tdb_do_delete().
00395 { 00396 struct tdb_traverse_lock *i; 00397 for (i = &tdb->travlocks; i; i = i->next) 00398 if (i->off == off) 00399 return -1; 00400 return tdb->methods->tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1, 1); 00401 }
int tdb_write_unlock_record | ( | struct tdb_context * | tdb, | |
tdb_off_t | off | |||
) |
参照先 tdb_context::methods・tdb・tdb_methods::tdb_brlock.
参照元 tdb_do_delete().
00408 { 00409 return tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0, 1); 00410 }
int tdb_ofs_read | ( | struct tdb_context * | tdb, | |
tdb_off_t | offset, | |||
tdb_off_t * | d | |||
) |
参照先 tdb_context::methods・tdb・tdb_methods::tdb_read.
参照元 remove_from_freelist()・tdb_allocate()・tdb_count_dead()・tdb_do_delete()・tdb_dump_chain()・tdb_dump_record()・tdb_find()・tdb_find_dead()・tdb_free()・tdb_get_seqnum()・tdb_increment_seqnum()・tdb_next_lock()・tdb_printfreelist()・tdb_purge_dead()・tdb_recovery_allocate()・tdb_store()・tdb_transaction_recover()・tdb_validate_freelist().
int tdb_ofs_write | ( | struct tdb_context * | tdb, | |
tdb_off_t | offset, | |||
tdb_off_t * | d | |||
) |
参照先 tdb_context::methods・tdb・tdb_methods::tdb_write.
参照元 remove_from_freelist()・tdb_allocate_ofs()・tdb_do_delete()・tdb_free()・tdb_increment_seqnum()・tdb_store()・tdb_transaction_recover()・update_tailer().
00370 { 00371 tdb_off_t off = *d; 00372 return tdb->methods->tdb_write(tdb, offset, CONVERT(off), sizeof(*d)); 00373 }
void* tdb_convert | ( | void * | buf, | |
u32 | size | |||
) |
参照元 tdb_open_ex()・tdb_read()・tdb_transaction_recover()・transaction_read()・transaction_setup_recovery().
00123 { 00124 u32 i, *p = (u32 *)buf; 00125 for (i = 0; i < size / 4; i++) 00126 p[i] = TDB_BYTEREV(p[i]); 00127 return buf; 00128 }
int tdb_free | ( | struct tdb_context * | tdb, | |
tdb_off_t | offset, | |||
struct list_struct * | rec | |||
) |
freelist.c の 95 行で定義されています。
参照先 tdb_header::hash_size・tdb_context::header・tdb_context::map_size・tdb_context::methods・tdb_context::next・list_struct::rec_len・remove_from_freelist()・tdb・TDB_DEBUG_FATAL・tdb_lock()・tdb_ofs_read()・tdb_ofs_write()・tdb_methods::tdb_read・tdb_rec_write()・tdb_unlock()・update_tailer().
参照元 tdb_allocate_ofs()・tdb_do_delete()・tdb_expand()・tdb_recovery_allocate().
00096 { 00097 tdb_off_t right, left; 00098 00099 /* Allocation and tailer lock */ 00100 if (tdb_lock(tdb, -1, F_WRLCK) != 0) 00101 return -1; 00102 00103 /* set an initial tailer, so if we fail we don't leave a bogus record */ 00104 if (update_tailer(tdb, offset, rec) != 0) { 00105 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed!\n")); 00106 goto fail; 00107 } 00108 00109 /* Look right first (I'm an Australian, dammit) */ 00110 right = offset + sizeof(*rec) + rec->rec_len; 00111 if (right + sizeof(*rec) <= tdb->map_size) { 00112 struct list_struct r; 00113 00114 if (tdb->methods->tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) { 00115 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right read failed at %u\n", right)); 00116 goto left; 00117 } 00118 00119 /* If it's free, expand to include it. */ 00120 if (r.magic == TDB_FREE_MAGIC) { 00121 if (remove_from_freelist(tdb, right, r.next) == -1) { 00122 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right free failed at %u\n", right)); 00123 goto left; 00124 } 00125 rec->rec_len += sizeof(r) + r.rec_len; 00126 } 00127 } 00128 00129 left: 00130 /* Look left */ 00131 left = offset - sizeof(tdb_off_t); 00132 if (left > TDB_DATA_START(tdb->header.hash_size)) { 00133 struct list_struct l; 00134 tdb_off_t leftsize; 00135 00136 /* Read in tailer and jump back to header */ 00137 if (tdb_ofs_read(tdb, left, &leftsize) == -1) { 00138 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left offset read failed at %u\n", left)); 00139 goto update; 00140 } 00141 00142 /* it could be uninitialised data */ 00143 if (leftsize == 0 || leftsize == TDB_PAD_U32) { 00144 goto update; 00145 } 00146 00147 left = offset - leftsize; 00148 00149 /* Now read in record */ 00150 if (tdb->methods->tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) { 00151 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left read failed at %u (%u)\n", left, leftsize)); 00152 goto update; 00153 } 00154 00155 /* If it's free, expand to include it. */ 00156 if (l.magic == TDB_FREE_MAGIC) { 00157 if (remove_from_freelist(tdb, left, l.next) == -1) { 00158 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left free failed at %u\n", left)); 00159 goto update; 00160 } else { 00161 offset = left; 00162 rec->rec_len += leftsize; 00163 } 00164 } 00165 } 00166 00167 update: 00168 if (update_tailer(tdb, offset, rec) == -1) { 00169 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset)); 00170 goto fail; 00171 } 00172 00173 /* Now, prepend to free list */ 00174 rec->magic = TDB_FREE_MAGIC; 00175 00176 if (tdb_ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 || 00177 tdb_rec_write(tdb, offset, rec) == -1 || 00178 tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) { 00179 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free record write failed at offset=%d\n", offset)); 00180 goto fail; 00181 } 00182 00183 /* And we're done. */ 00184 tdb_unlock(tdb, -1, F_WRLCK); 00185 return 0; 00186 00187 fail: 00188 tdb_unlock(tdb, -1, F_WRLCK); 00189 return -1; 00190 }
tdb_off_t tdb_allocate | ( | struct tdb_context * | tdb, | |
tdb_len_t | length, | |||
struct list_struct * | rec | |||
) |
freelist.c の 258 行で定義されています。
参照先 last_ptr・list_struct::next・rec_free_read()・list_struct::rec_len・tdb・tdb_allocate_ofs()・tdb_expand()・tdb_lock()・tdb_ofs_read()・tdb_unlock().
参照元 tdb_store().
00259 { 00260 tdb_off_t rec_ptr, last_ptr, newrec_ptr; 00261 struct { 00262 tdb_off_t rec_ptr, last_ptr; 00263 tdb_len_t rec_len; 00264 } bestfit; 00265 00266 if (tdb_lock(tdb, -1, F_WRLCK) == -1) 00267 return 0; 00268 00269 /* Extra bytes required for tailer */ 00270 length += sizeof(tdb_off_t); 00271 00272 again: 00273 last_ptr = FREELIST_TOP; 00274 00275 /* read in the freelist top */ 00276 if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) 00277 goto fail; 00278 00279 bestfit.rec_ptr = 0; 00280 bestfit.last_ptr = 0; 00281 bestfit.rec_len = 0; 00282 00283 /* 00284 this is a best fit allocation strategy. Originally we used 00285 a first fit strategy, but it suffered from massive fragmentation 00286 issues when faced with a slowly increasing record size. 00287 */ 00288 while (rec_ptr) { 00289 if (rec_free_read(tdb, rec_ptr, rec) == -1) { 00290 goto fail; 00291 } 00292 00293 if (rec->rec_len >= length) { 00294 if (bestfit.rec_ptr == 0 || 00295 rec->rec_len < bestfit.rec_len) { 00296 bestfit.rec_len = rec->rec_len; 00297 bestfit.rec_ptr = rec_ptr; 00298 bestfit.last_ptr = last_ptr; 00299 /* consider a fit to be good enough if 00300 we aren't wasting more than half 00301 the space */ 00302 if (bestfit.rec_len < 2*length) { 00303 break; 00304 } 00305 } 00306 } 00307 00308 /* move to the next record */ 00309 last_ptr = rec_ptr; 00310 rec_ptr = rec->next; 00311 } 00312 00313 if (bestfit.rec_ptr != 0) { 00314 if (rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) { 00315 goto fail; 00316 } 00317 00318 newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr, rec, bestfit.last_ptr); 00319 tdb_unlock(tdb, -1, F_WRLCK); 00320 return newrec_ptr; 00321 } 00322 00323 /* we didn't find enough space. See if we can expand the 00324 database and if we can then try again */ 00325 if (tdb_expand(tdb, length + sizeof(*rec)) == 0) 00326 goto again; 00327 fail: 00328 tdb_unlock(tdb, -1, F_WRLCK); 00329 return 0; 00330 }
int tdb_lock_record | ( | struct tdb_context * | tdb, | |
tdb_off_t | off | |||
) |
参照先 tdb_context::methods・tdb・tdb_methods::tdb_brlock.
参照元 tdb_next_lock()・tdb_nextkey().
00385 { 00386 return off ? tdb->methods->tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0, 1) : 0; 00387 }
int tdb_unlock_record | ( | struct tdb_context * | tdb, | |
tdb_off_t | off | |||
) |
参照先 tdb_context::methods・tdb_traverse_lock::next・tdb_traverse_lock::off・tdb・tdb_methods::tdb_brlock・tdb_context::travlocks.
参照元 tdb_firstkey()・tdb_next_lock()・tdb_nextkey()・tdb_traverse_internal().
00414 { 00415 struct tdb_traverse_lock *i; 00416 u32 count = 0; 00417 00418 if (off == 0) 00419 return 0; 00420 for (i = &tdb->travlocks; i; i = i->next) 00421 if (i->off == off) 00422 count++; 00423 return (count == 1 ? tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0, 1) : 0); 00424 }
int tdb_rec_read | ( | struct tdb_context * | tdb, | |
tdb_off_t | offset, | |||
struct list_struct * | rec | |||
) |
参照先 tdb_context::ecode・tdb_context::methods・tdb_context::next・tdb・TDB_DEBUG_FATAL・TDB_ERR_CORRUPT・tdb_methods::tdb_oob・tdb_methods::tdb_read.
参照元 tdb_count_dead()・tdb_do_delete()・tdb_find()・tdb_find_dead()・tdb_next_lock()・tdb_nextkey()・tdb_purge_dead().
00436 { 00437 if (tdb->methods->tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1) 00438 return -1; 00439 if (TDB_BAD_MAGIC(rec)) { 00440 /* Ensure ecode is set for log fn. */ 00441 tdb->ecode = TDB_ERR_CORRUPT; 00442 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset)); 00443 return TDB_ERRCODE(TDB_ERR_CORRUPT, -1); 00444 } 00445 return tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0); 00446 }
int tdb_rec_write | ( | struct tdb_context * | tdb, | |
tdb_off_t | offset, | |||
struct list_struct * | rec | |||
) |
参照先 tdb_context::methods・tdb・tdb_methods::tdb_write.
参照元 tdb_allocate_ofs()・tdb_delete_hash()・tdb_do_delete()・tdb_free()・tdb_store()・tdb_update_hash().
00449 { 00450 struct list_struct r = *rec; 00451 return tdb->methods->tdb_write(tdb, offset, CONVERT(r), sizeof(r)); 00452 }
int tdb_do_delete | ( | struct tdb_context * | tdb, | |
tdb_off_t | rec_ptr, | |||
struct list_struct * | rec | |||
) |
参照先 list_struct::full_hash・last_ptr・list_struct::magic・list_struct::next・tdb_context::read_only・tdb・tdb_free()・tdb_ofs_read()・tdb_ofs_write()・tdb_rec_read()・tdb_rec_write()・tdb_write_lock_record()・tdb_write_unlock_record()・tdb_context::traverse_read.
参照元 tdb_delete_hash()・tdb_next_lock()・tdb_purge_dead().
00228 { 00229 tdb_off_t last_ptr, i; 00230 struct list_struct lastrec; 00231 00232 if (tdb->read_only || tdb->traverse_read) return -1; 00233 00234 if (tdb_write_lock_record(tdb, rec_ptr) == -1) { 00235 /* Someone traversing here: mark it as dead */ 00236 rec->magic = TDB_DEAD_MAGIC; 00237 return tdb_rec_write(tdb, rec_ptr, rec); 00238 } 00239 if (tdb_write_unlock_record(tdb, rec_ptr) != 0) 00240 return -1; 00241 00242 /* find previous record in hash chain */ 00243 if (tdb_ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1) 00244 return -1; 00245 for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next) 00246 if (tdb_rec_read(tdb, i, &lastrec) == -1) 00247 return -1; 00248 00249 /* unlink it: next ptr is at start of record. */ 00250 if (last_ptr == 0) 00251 last_ptr = TDB_HASH_TOP(rec->full_hash); 00252 if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) 00253 return -1; 00254 00255 /* recover the space */ 00256 if (tdb_free(tdb, rec_ptr, rec) == -1) 00257 return -1; 00258 return 0; 00259 }
char* tdb_alloc_read | ( | struct tdb_context * | tdb, | |
tdb_off_t | offset, | |||
tdb_len_t | len | |||
) |
参照先 buf・tdb_context::ecode・errno・tdb_context::methods・strerror()・tdb・TDB_DEBUG_ERROR・TDB_ERR_OOM・tdb_methods::tdb_read.
参照元 tdb_fetch()・tdb_firstkey()・tdb_nextkey()・tdb_parse_data()・tdb_traverse_internal().
00378 { 00379 char *buf; 00380 00381 /* some systems don't like zero length malloc */ 00382 if (len == 0) { 00383 len = 1; 00384 } 00385 00386 if (!(buf = (char *)malloc(len))) { 00387 /* Ensure ecode is set for log fn. */ 00388 tdb->ecode = TDB_ERR_OOM; 00389 TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%d (%s)\n", 00390 len, strerror(errno))); 00391 return TDB_ERRCODE(TDB_ERR_OOM, buf); 00392 } 00393 if (tdb->methods->tdb_read(tdb, offset, buf, len, 0) == -1) { 00394 SAFE_FREE(buf); 00395 return NULL; 00396 } 00397 return buf; 00398 }
int tdb_parse_data | ( | struct tdb_context * | tdb, | |
TDB_DATA | key, | |||
tdb_off_t | offset, | |||
tdb_len_t | len, | |||
int(*)(TDB_DATA key, TDB_DATA data, void *private_data) | parser, | |||
void * | private_data | |||
) |
参照先 TDB_DATA::dptr・TDB_DATA::dsize・tdb_context::map_ptr・tdb_context::methods・result・tdb・tdb_alloc_read()・tdb_methods::tdb_oob・tdb_context::transaction.
参照元 tdb_find()・tdb_parse_record().
00407 { 00408 TDB_DATA data; 00409 int result; 00410 00411 data.dsize = len; 00412 00413 if ((tdb->transaction == NULL) && (tdb->map_ptr != NULL)) { 00414 /* 00415 * Optimize by avoiding the malloc/memcpy/free, point the 00416 * parser directly at the mmap area. 00417 */ 00418 if (tdb->methods->tdb_oob(tdb, offset+len, 0) != 0) { 00419 return -1; 00420 } 00421 data.dptr = offset + (char *)tdb->map_ptr; 00422 return parser(key, data, private_data); 00423 } 00424 00425 if (!(data.dptr = tdb_alloc_read(tdb, offset, len))) { 00426 return -1; 00427 } 00428 00429 result = parser(key, data, private_data); 00430 free(data.dptr); 00431 return result; 00432 }
tdb_off_t tdb_find_lock_hash | ( | struct tdb_context * | tdb, | |
TDB_DATA | key, | |||
u32 | hash, | |||
int | locktype, | |||
struct list_struct * | rec | |||
) |
参照先 tdb・tdb_find()・tdb_lock()・tdb_unlock().
参照元 tdb_delete_hash()・tdb_exists_hash()・tdb_fetch()・tdb_nextkey()・tdb_parse_record().
00095 { 00096 u32 rec_ptr; 00097 00098 if (tdb_lock(tdb, BUCKET(hash), locktype) == -1) 00099 return 0; 00100 if (!(rec_ptr = tdb_find(tdb, key, hash, rec))) 00101 tdb_unlock(tdb, BUCKET(hash), locktype); 00102 return rec_ptr; 00103 }
void tdb_io_init | ( | struct tdb_context * | tdb | ) |
参照先 io_methods・tdb_context::methods・tdb.
参照元 tdb_open_ex().
00467 { 00468 tdb->methods = &io_methods; 00469 }
int tdb_expand | ( | struct tdb_context * | tdb, | |
tdb_off_t | size | |||
) |
参照先 tdb_context::flags・tdb_context::map_size・tdb_context::methods・tdb_context::page_size・tdb・TDB_DEBUG_ERROR・tdb_free()・tdb_lock()・tdb_mmap()・tdb_munmap()・tdb_methods::tdb_oob・tdb_unlock().
参照元 tdb_allocate().
00295 { 00296 struct list_struct rec; 00297 tdb_off_t offset; 00298 00299 if (tdb_lock(tdb, -1, F_WRLCK) == -1) { 00300 TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n")); 00301 return -1; 00302 } 00303 00304 /* must know about any previous expansions by another process */ 00305 tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1); 00306 00307 /* always make room for at least 10 more records, and round 00308 the database up to a multiple of the page size */ 00309 size = TDB_ALIGN(tdb->map_size + size*10, tdb->page_size) - tdb->map_size; 00310 00311 if (!(tdb->flags & TDB_INTERNAL)) 00312 tdb_munmap(tdb); 00313 00314 /* 00315 * We must ensure the file is unmapped before doing this 00316 * to ensure consistency with systems like OpenBSD where 00317 * writes and mmaps are not consistent. 00318 */ 00319 00320 /* expand the file itself */ 00321 if (!(tdb->flags & TDB_INTERNAL)) { 00322 if (tdb->methods->tdb_expand_file(tdb, tdb->map_size, size) != 0) 00323 goto fail; 00324 } 00325 00326 tdb->map_size += size; 00327 00328 if (tdb->flags & TDB_INTERNAL) { 00329 char *new_map_ptr = (char *)realloc(tdb->map_ptr, 00330 tdb->map_size); 00331 if (!new_map_ptr) { 00332 tdb->map_size -= size; 00333 goto fail; 00334 } 00335 tdb->map_ptr = new_map_ptr; 00336 } else { 00337 /* 00338 * We must ensure the file is remapped before adding the space 00339 * to ensure consistency with systems like OpenBSD where 00340 * writes and mmaps are not consistent. 00341 */ 00342 00343 /* We're ok if the mmap fails as we'll fallback to read/write */ 00344 tdb_mmap(tdb); 00345 } 00346 00347 /* form a new freelist record */ 00348 memset(&rec,'\0',sizeof(rec)); 00349 rec.rec_len = size - sizeof(rec); 00350 00351 /* link it into the free list */ 00352 offset = tdb->map_size - size; 00353 if (tdb_free(tdb, offset, &rec) == -1) 00354 goto fail; 00355 00356 tdb_unlock(tdb, -1, F_WRLCK); 00357 return 0; 00358 fail: 00359 tdb_unlock(tdb, -1, F_WRLCK); 00360 return -1; 00361 }
int rec_free_read | ( | struct tdb_context * | tdb, | |
tdb_off_t | off, | |||
struct list_struct * | rec | |||
) |
freelist.c の 32 行で定義されています。
参照先 tdb_context::ecode・tdb_context::methods・tdb_context::next・tdb・TDB_DEBUG_WARNING・TDB_ERR_CORRUPT・tdb_methods::tdb_oob・tdb_methods::tdb_read.
参照元 tdb_allocate()・tdb_validate_freelist().
00033 { 00034 if (tdb->methods->tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1) 00035 return -1; 00036 00037 if (rec->magic == TDB_MAGIC) { 00038 /* this happens when a app is showdown while deleting a record - we should 00039 not completely fail when this happens */ 00040 TDB_LOG((tdb, TDB_DEBUG_WARNING, "rec_free_read non-free magic 0x%x at offset=%d - fixing\n", 00041 rec->magic, off)); 00042 rec->magic = TDB_FREE_MAGIC; 00043 if (tdb->methods->tdb_write(tdb, off, rec, sizeof(*rec)) == -1) 00044 return -1; 00045 } 00046 00047 if (rec->magic != TDB_FREE_MAGIC) { 00048 /* Ensure ecode is set for log fn. */ 00049 tdb->ecode = TDB_ERR_CORRUPT; 00050 TDB_LOG((tdb, TDB_DEBUG_WARNING, "rec_free_read bad magic 0x%x at offset=%d\n", 00051 rec->magic, off)); 00052 return TDB_ERRCODE(TDB_ERR_CORRUPT, -1); 00053 } 00054 if (tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0) != 0) 00055 return -1; 00056 return 0; 00057 }