関数 | |
static int | tdb_next_lock (struct tdb_context *tdb, struct tdb_traverse_lock *tlock, struct list_struct *rec) |
static int | tdb_traverse_internal (struct tdb_context *tdb, tdb_traverse_func fn, void *private_data, struct tdb_traverse_lock *tl) |
int | tdb_traverse_read (struct tdb_context *tdb, tdb_traverse_func fn, void *private_data) |
int | tdb_traverse (struct tdb_context *tdb, tdb_traverse_func fn, void *private_data) |
TDB_DATA | tdb_firstkey (struct tdb_context *tdb) |
TDB_DATA | tdb_nextkey (struct tdb_context *tdb, TDB_DATA oldkey) |
static int tdb_next_lock | ( | struct tdb_context * | tdb, | |
struct tdb_traverse_lock * | tlock, | |||
struct list_struct * | rec | |||
) | [static] |
traverse.c の 32 行で定義されています。
参照先 tdb_traverse_lock::hash・tdb_header::hash_size・tdb_context::header・tdb_traverse_lock::lock_rw・tdb_context::methods・list_struct::next・tdb_methods::next_hash_chain・tdb_traverse_lock::off・tdb_context::read_only・tdb・TDB_DEBUG_FATAL・tdb_do_delete()・tdb_lock()・tdb_lock_record()・tdb_ofs_read()・tdb_rec_read()・tdb_unlock()・tdb_unlock_record()・tdb_context::traverse_read.
参照元 tdb_firstkey()・tdb_nextkey()・tdb_traverse_internal().
00034 { 00035 int want_next = (tlock->off != 0); 00036 00037 /* Lock each chain from the start one. */ 00038 for (; tlock->hash < tdb->header.hash_size; tlock->hash++) { 00039 if (!tlock->off && tlock->hash != 0) { 00040 /* this is an optimisation for the common case where 00041 the hash chain is empty, which is particularly 00042 common for the use of tdb with ldb, where large 00043 hashes are used. In that case we spend most of our 00044 time in tdb_brlock(), locking empty hash chains. 00045 00046 To avoid this, we do an unlocked pre-check to see 00047 if the hash chain is empty before starting to look 00048 inside it. If it is empty then we can avoid that 00049 hash chain. If it isn't empty then we can't believe 00050 the value we get back, as we read it without a 00051 lock, so instead we get the lock and re-fetch the 00052 value below. 00053 00054 Notice that not doing this optimisation on the 00055 first hash chain is critical. We must guarantee 00056 that we have done at least one fcntl lock at the 00057 start of a search to guarantee that memory is 00058 coherent on SMP systems. If records are added by 00059 others during the search then thats OK, and we 00060 could possibly miss those with this trick, but we 00061 could miss them anyway without this trick, so the 00062 semantics don't change. 00063 00064 With a non-indexed ldb search this trick gains us a 00065 factor of around 80 in speed on a linux 2.6.x 00066 system (testing using ldbtest). 00067 */ 00068 tdb->methods->next_hash_chain(tdb, &tlock->hash); 00069 if (tlock->hash == tdb->header.hash_size) { 00070 continue; 00071 } 00072 } 00073 00074 if (tdb_lock(tdb, tlock->hash, tlock->lock_rw) == -1) 00075 return -1; 00076 00077 /* No previous record? Start at top of chain. */ 00078 if (!tlock->off) { 00079 if (tdb_ofs_read(tdb, TDB_HASH_TOP(tlock->hash), 00080 &tlock->off) == -1) 00081 goto fail; 00082 } else { 00083 /* Otherwise unlock the previous record. */ 00084 if (tdb_unlock_record(tdb, tlock->off) != 0) 00085 goto fail; 00086 } 00087 00088 if (want_next) { 00089 /* We have offset of old record: grab next */ 00090 if (tdb_rec_read(tdb, tlock->off, rec) == -1) 00091 goto fail; 00092 tlock->off = rec->next; 00093 } 00094 00095 /* Iterate through chain */ 00096 while( tlock->off) { 00097 tdb_off_t current; 00098 if (tdb_rec_read(tdb, tlock->off, rec) == -1) 00099 goto fail; 00100 00101 /* Detect infinite loops. From "Shlomi Yaakobovich" <Shlomi@exanet.com>. */ 00102 if (tlock->off == rec->next) { 00103 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: loop detected.\n")); 00104 goto fail; 00105 } 00106 00107 if (!TDB_DEAD(rec)) { 00108 /* Woohoo: we found one! */ 00109 if (tdb_lock_record(tdb, tlock->off) != 0) 00110 goto fail; 00111 return tlock->off; 00112 } 00113 00114 /* Try to clean dead ones from old traverses */ 00115 current = tlock->off; 00116 tlock->off = rec->next; 00117 if (!(tdb->read_only || tdb->traverse_read) && 00118 tdb_do_delete(tdb, current, rec) != 0) 00119 goto fail; 00120 } 00121 tdb_unlock(tdb, tlock->hash, tlock->lock_rw); 00122 want_next = 0; 00123 } 00124 /* We finished iteration without finding anything */ 00125 return TDB_ERRCODE(TDB_SUCCESS, 0); 00126 00127 fail: 00128 tlock->off = 0; 00129 if (tdb_unlock(tdb, tlock->hash, tlock->lock_rw) != 0) 00130 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: On error unlock failed!\n")); 00131 return -1; 00132 }
static int tdb_traverse_internal | ( | struct tdb_context * | tdb, | |
tdb_traverse_func | fn, | |||
void * | private_data, | |||
struct tdb_traverse_lock * | tl | |||
) | [static] |
traverse.c の 139 行で定義されています。
参照先 TDB_DATA::dptr・TDB_DATA::dsize・fn・tdb_traverse_lock::hash・tdb_traverse_lock::lock_rw・tdb_traverse_lock::next・tdb_traverse_lock::off・tdb・tdb_alloc_read()・TDB_DEBUG_FATAL・tdb_next_lock()・tdb_unlock()・tdb_unlock_record()・tdb_context::travlocks.
参照元 tdb_traverse()・tdb_traverse_read().
00142 { 00143 TDB_DATA key, dbuf; 00144 struct list_struct rec; 00145 int ret, count = 0; 00146 00147 /* This was in the initializaton, above, but the IRIX compiler 00148 * did not like it. crh 00149 */ 00150 tl->next = tdb->travlocks.next; 00151 00152 /* fcntl locks don't stack: beware traverse inside traverse */ 00153 tdb->travlocks.next = tl; 00154 00155 /* tdb_next_lock places locks on the record returned, and its chain */ 00156 while ((ret = tdb_next_lock(tdb, tl, &rec)) > 0) { 00157 count++; 00158 /* now read the full record */ 00159 key.dptr = tdb_alloc_read(tdb, tl->off + sizeof(rec), 00160 rec.key_len + rec.data_len); 00161 if (!key.dptr) { 00162 ret = -1; 00163 if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0) 00164 goto out; 00165 if (tdb_unlock_record(tdb, tl->off) != 0) 00166 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n")); 00167 goto out; 00168 } 00169 key.dsize = rec.key_len; 00170 dbuf.dptr = key.dptr + rec.key_len; 00171 dbuf.dsize = rec.data_len; 00172 00173 /* Drop chain lock, call out */ 00174 if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0) { 00175 ret = -1; 00176 SAFE_FREE(key.dptr); 00177 goto out; 00178 } 00179 if (fn && fn(tdb, key, dbuf, private_data)) { 00180 /* They want us to terminate traversal */ 00181 ret = count; 00182 if (tdb_unlock_record(tdb, tl->off) != 0) { 00183 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: unlock_record failed!\n"));; 00184 ret = -1; 00185 } 00186 SAFE_FREE(key.dptr); 00187 goto out; 00188 } 00189 SAFE_FREE(key.dptr); 00190 } 00191 out: 00192 tdb->travlocks.next = tl->next; 00193 if (ret < 0) 00194 return -1; 00195 else 00196 return count; 00197 }
int tdb_traverse_read | ( | struct tdb_context * | tdb, | |
tdb_traverse_func | fn, | |||
void * | private_data | |||
) |
traverse.c の 203 行で定義されています。
参照先 tdb_context::ecode・tdb_context::methods・tdb・tdb_methods::tdb_brlock・TDB_DEBUG_ERROR・TDB_ERR_LOCK・tdb_traverse_internal()・tdb_context::traverse_read.
参照元 addrec_db()・main()・tdb_traverse().
00205 { 00206 struct tdb_traverse_lock tl = { NULL, 0, 0, F_RDLCK }; 00207 int ret; 00208 00209 /* we need to get a read lock on the transaction lock here to 00210 cope with the lock ordering semantics of solaris10 */ 00211 if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1) { 00212 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_traverse_read: failed to get transaction lock\n")); 00213 tdb->ecode = TDB_ERR_LOCK; 00214 return -1; 00215 } 00216 00217 tdb->traverse_read++; 00218 ret = tdb_traverse_internal(tdb, fn, private_data, &tl); 00219 tdb->traverse_read--; 00220 00221 tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1); 00222 00223 return ret; 00224 }
int tdb_traverse | ( | struct tdb_context * | tdb, | |
tdb_traverse_func | fn, | |||
void * | private_data | |||
) |
traverse.c の 230 行で定義されています。
参照先 tdb_context::ecode・tdb_context::methods・tdb_context::read_only・tdb・tdb_methods::tdb_brlock・TDB_DEBUG_ERROR・TDB_ERR_LOCK・tdb_traverse_internal()・tdb_traverse_read()・tdb_context::traverse_read.
参照元 addrec_db()・backup_tdb()・brl_forall()・clear_unexpected()・count_current_connections()・do_command()・do_daemon_stack_trace()・dump_tdb()・dump_wins_subnet_namelist()・elog_tdb_size()・enum_aliasmem()・fetch_all_active_wins_1b_names()・idmap_tdb_convert()・idmap_tdb_dump_data()・info_tdb()・init_group_mapping()・initiate_wins_processing()・load_msg()・main()・message_send_all()・net_enum_pipes()・net_idmap_dump()・net_status_sessions()・net_status_shares()・net_status_shares_parseable()・print_backend_init()・print_queue_update_internal()・privilege_enumerate_accounts()・py_tdb_hnd_keys()・py_tdb_hnd_traverse()・receive_unexpected()・session_traverse()・share_info_db_init()・share_mode_forall()・status_page()・sysjob_to_jobid()・tdb_hnd_length()・tdbsam_setsampwent()・update_c_setprinter()・upgrade_to_version_4()・upgrade_to_version_5()・verify_tdb()・wcache_count_cached_creds()・wcache_flush_cache()・wcache_invalidate_cache()・wcache_remove_oldest_cached_creds()・wins_write_database().
00232 { 00233 struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK }; 00234 int ret; 00235 00236 if (tdb->read_only || tdb->traverse_read) { 00237 return tdb_traverse_read(tdb, fn, private_data); 00238 } 00239 00240 if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) { 00241 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_traverse: failed to get transaction lock\n")); 00242 tdb->ecode = TDB_ERR_LOCK; 00243 return -1; 00244 } 00245 00246 ret = tdb_traverse_internal(tdb, fn, private_data, &tl); 00247 00248 tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1); 00249 00250 return ret; 00251 }
TDB_DATA tdb_firstkey | ( | struct tdb_context * | tdb | ) |
traverse.c の 255 行で定義されています。
参照先 TDB_DATA::dptr・TDB_DATA::dsize・tdb_traverse_lock::hash・list_struct::key_len・tdb_traverse_lock::lock_rw・tdb_traverse_lock::off・tdb・tdb_alloc_read()・TDB_DEBUG_FATAL・tdb_next_lock()・tdb_null・tdb_unlock()・tdb_unlock_record()・tdb_context::travlocks.
参照元 compare_db()・enum_group_mapping()・first_record()・get_group_map_from_gid()・get_group_map_from_ntname()・get_ntdrivers()・get_ntforms()・py_tdb_hnd_first_key()・tdb_search_keys()・tdbsam_convert()・upgrade_to_version_3().
00256 { 00257 TDB_DATA key; 00258 struct list_struct rec; 00259 00260 /* release any old lock */ 00261 if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0) 00262 return tdb_null; 00263 tdb->travlocks.off = tdb->travlocks.hash = 0; 00264 tdb->travlocks.lock_rw = F_RDLCK; 00265 00266 /* Grab first record: locks chain and returned record. */ 00267 if (tdb_next_lock(tdb, &tdb->travlocks, &rec) <= 0) 00268 return tdb_null; 00269 /* now read the key */ 00270 key.dsize = rec.key_len; 00271 key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize); 00272 00273 /* Unlock the hash chain of the record we just read. */ 00274 if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) 00275 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_firstkey: error occurred while tdb_unlocking!\n")); 00276 return key; 00277 }
TDB_DATA tdb_nextkey | ( | struct tdb_context * | tdb, | |
TDB_DATA | oldkey | |||
) |
traverse.c の 280 行で定義されています。
参照先 TDB_DATA::dptr・TDB_DATA::dsize・errno・list_struct::full_hash・tdb_traverse_lock::hash・tdb_context::hash_fn・list_struct::key_len・tdb_traverse_lock::lock_rw・tdb_traverse_lock::off・strerror()・tdb・tdb_alloc_read()・TDB_DEBUG_FATAL・tdb_find_lock_hash()・tdb_lock()・tdb_lock_record()・tdb_next_lock()・tdb_null・tdb_rec_read()・tdb_unlock()・tdb_unlock_record()・tdb_context::travlocks.
参照元 compare_db()・enum_group_mapping()・get_group_map_from_gid()・get_group_map_from_ntname()・get_ntdrivers()・get_ntforms()・next_record()・py_tdb_hnd_next_key()・tdb_search_keys()・tdbsam_convert()・upgrade_to_version_3().
00281 { 00282 u32 oldhash; 00283 TDB_DATA key = tdb_null; 00284 struct list_struct rec; 00285 char *k = NULL; 00286 00287 /* Is locked key the old key? If so, traverse will be reliable. */ 00288 if (tdb->travlocks.off) { 00289 if (tdb_lock(tdb,tdb->travlocks.hash,tdb->travlocks.lock_rw)) 00290 return tdb_null; 00291 if (tdb_rec_read(tdb, tdb->travlocks.off, &rec) == -1 00292 || !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec), 00293 rec.key_len)) 00294 || memcmp(k, oldkey.dptr, oldkey.dsize) != 0) { 00295 /* No, it wasn't: unlock it and start from scratch */ 00296 if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0) { 00297 SAFE_FREE(k); 00298 return tdb_null; 00299 } 00300 if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) { 00301 SAFE_FREE(k); 00302 return tdb_null; 00303 } 00304 tdb->travlocks.off = 0; 00305 } 00306 00307 SAFE_FREE(k); 00308 } 00309 00310 if (!tdb->travlocks.off) { 00311 /* No previous element: do normal find, and lock record */ 00312 tdb->travlocks.off = tdb_find_lock_hash(tdb, oldkey, tdb->hash_fn(&oldkey), tdb->travlocks.lock_rw, &rec); 00313 if (!tdb->travlocks.off) 00314 return tdb_null; 00315 tdb->travlocks.hash = BUCKET(rec.full_hash); 00316 if (tdb_lock_record(tdb, tdb->travlocks.off) != 0) { 00317 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno))); 00318 return tdb_null; 00319 } 00320 } 00321 oldhash = tdb->travlocks.hash; 00322 00323 /* Grab next record: locks chain and returned record, 00324 unlocks old record */ 00325 if (tdb_next_lock(tdb, &tdb->travlocks, &rec) > 0) { 00326 key.dsize = rec.key_len; 00327 key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec), 00328 key.dsize); 00329 /* Unlock the chain of this new record */ 00330 if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) 00331 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n")); 00332 } 00333 /* Unlock the chain of old record */ 00334 if (tdb_unlock(tdb, BUCKET(oldhash), tdb->travlocks.lock_rw) != 0) 00335 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n")); 00336 return key; 00337 }