tdb/common/freelist.c

ソースコードを見る。

関数

int rec_free_read (struct tdb_context *tdb, tdb_off_t off, struct list_struct *rec)
static int remove_from_freelist (struct tdb_context *tdb, tdb_off_t off, tdb_off_t next)
static int update_tailer (struct tdb_context *tdb, tdb_off_t offset, const struct list_struct *rec)
int tdb_free (struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec)
static tdb_off_t tdb_allocate_ofs (struct tdb_context *tdb, tdb_len_t length, tdb_off_t rec_ptr, struct list_struct *rec, tdb_off_t last_ptr)
tdb_off_t tdb_allocate (struct tdb_context *tdb, tdb_len_t length, struct list_struct *rec)


関数

int rec_free_read ( struct tdb_context tdb,
tdb_off_t  off,
struct list_struct rec 
)

freelist.c32 行で定義されています。

参照先 tdb_context::ecodetdb_context::methodstdb_context::nexttdbTDB_DEBUG_WARNINGTDB_ERR_CORRUPTtdb_methods::tdb_oobtdb_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 }

static int remove_from_freelist ( struct tdb_context tdb,
tdb_off_t  off,
tdb_off_t  next 
) [static]

freelist.c62 行で定義されています。

参照先 last_ptrtdbTDB_DEBUG_FATALTDB_ERR_CORRUPTtdb_ofs_read()tdb_ofs_write().

参照元 tdb_free().

00063 {
00064         tdb_off_t last_ptr, i;
00065 
00066         /* read in the freelist top */
00067         last_ptr = FREELIST_TOP;
00068         while (tdb_ofs_read(tdb, last_ptr, &i) != -1 && i != 0) {
00069                 if (i == off) {
00070                         /* We've found it! */
00071                         return tdb_ofs_write(tdb, last_ptr, &next);
00072                 }
00073                 /* Follow chain (next offset is at start of record) */
00074                 last_ptr = i;
00075         }
00076         TDB_LOG((tdb, TDB_DEBUG_FATAL,"remove_from_freelist: not on list at off=%d\n", off));
00077         return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
00078 }

static int update_tailer ( struct tdb_context tdb,
tdb_off_t  offset,
const struct list_struct rec 
) [static]

freelist.c82 行で定義されています。

参照先 list_struct::rec_lentdbtdb_ofs_write().

参照元 tdb_allocate_ofs()tdb_free().

00084 {
00085         tdb_off_t totalsize;
00086 
00087         /* Offset of tailer from record header */
00088         totalsize = sizeof(*rec) + rec->rec_len;
00089         return tdb_ofs_write(tdb, offset + totalsize - sizeof(tdb_off_t),
00090                          &totalsize);
00091 }

int tdb_free ( struct tdb_context tdb,
tdb_off_t  offset,
struct list_struct rec 
)

freelist.c95 行で定義されています。

参照先 tdb_header::hash_sizetdb_context::headertdb_context::map_sizetdb_context::methodstdb_context::nextlist_struct::rec_lenremove_from_freelist()tdbTDB_DEBUG_FATALtdb_lock()tdb_ofs_read()tdb_ofs_write()tdb_methods::tdb_readtdb_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 }

static tdb_off_t tdb_allocate_ofs ( struct tdb_context tdb,
tdb_len_t  length,
tdb_off_t  rec_ptr,
struct list_struct rec,
tdb_off_t  last_ptr 
) [static]

freelist.c197 行で定義されています。

参照先 list_struct::magiclist_struct::nextlist_struct::rec_lentdbtdb_free()tdb_ofs_write()tdb_rec_write()update_tailer().

参照元 tdb_allocate().

00199 {
00200         struct list_struct newrec;
00201         tdb_off_t newrec_ptr;
00202 
00203         memset(&newrec, '\0', sizeof(newrec));
00204 
00205         /* found it - now possibly split it up  */
00206         if (rec->rec_len > length + MIN_REC_SIZE) {
00207                 /* Length of left piece */
00208                 length = TDB_ALIGN(length, TDB_ALIGNMENT);
00209                 
00210                 /* Right piece to go on free list */
00211                 newrec.rec_len = rec->rec_len - (sizeof(*rec) + length);
00212                 newrec_ptr = rec_ptr + sizeof(*rec) + length;
00213                 
00214                 /* And left record is shortened */
00215                 rec->rec_len = length;
00216         } else {
00217                 newrec_ptr = 0;
00218         }
00219         
00220         /* Remove allocated record from the free list */
00221         if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) {
00222                 return 0;
00223         }
00224         
00225         /* Update header: do this before we drop alloc
00226            lock, otherwise tdb_free() might try to
00227            merge with us, thinking we're free.
00228            (Thanks Jeremy Allison). */
00229         rec->magic = TDB_MAGIC;
00230         if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
00231                 return 0;
00232         }
00233         
00234         /* Did we create new block? */
00235         if (newrec_ptr) {
00236                 /* Update allocated record tailer (we
00237                    shortened it). */
00238                 if (update_tailer(tdb, rec_ptr, rec) == -1) {
00239                         return 0;
00240                 }
00241                 
00242                 /* Free new record */
00243                 if (tdb_free(tdb, newrec_ptr, &newrec) == -1) {
00244                         return 0;
00245                 }
00246         }
00247         
00248         /* all done - return the new record offset */
00249         return rec_ptr;
00250 }

tdb_off_t tdb_allocate ( struct tdb_context tdb,
tdb_len_t  length,
struct list_struct rec 
)

freelist.c258 行で定義されています。

参照先 last_ptrlist_struct::nextrec_free_read()list_struct::rec_lentdbtdb_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 }


Sambaに対してSat Aug 29 21:24:30 2009に生成されました。  doxygen 1.4.7