00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 #include <string.h>
00015 #endif
00016
00017 #include "db_int.h"
00018 #include "dbinc/db_shash.h"
00019 #include "dbinc/mp.h"
00020
00021 static void __memp_bad_buffer __P((DB_MPOOL_HASH *));
00022
00023
00024
00025
00026
00027
00028
00029
00030 int
00031 __memp_alloc(dbmp, infop, mfp, len, offsetp, retp)
00032 DB_MPOOL *dbmp;
00033 REGINFO *infop;
00034 MPOOLFILE *mfp;
00035 size_t len;
00036 roff_t *offsetp;
00037 void *retp;
00038 {
00039 BH *bhp;
00040 DB_ENV *dbenv;
00041 DB_MPOOL_HASH *dbht, *hp, *hp_end, *hp_tmp;
00042 MPOOL *c_mp;
00043 MPOOLFILE *bh_mfp;
00044 size_t freed_space;
00045 db_mutex_t mutex;
00046 u_int32_t buckets, buffers, high_priority, priority;
00047 u_int32_t put_counter, total_buckets;
00048 int aggressive, giveup, ret;
00049 void *p;
00050
00051 dbenv = dbmp->dbenv;
00052 c_mp = infop->primary;
00053 dbht = R_ADDR(infop, c_mp->htab);
00054 hp_end = &dbht[c_mp->htab_buckets];
00055
00056 buckets = buffers = put_counter = total_buckets = 0;
00057 aggressive = giveup = 0;
00058 hp_tmp = NULL;
00059
00060 c_mp->stat.st_alloc++;
00061
00062
00063
00064
00065
00066
00067
00068
00069 if (mfp != NULL)
00070 len = (sizeof(BH) - sizeof(u_int8_t)) + mfp->stat.st_pagesize;
00071
00072 MPOOL_REGION_LOCK(dbenv, infop);
00073
00074
00075
00076
00077
00078 high_priority = c_mp->lru_count - c_mp->stat.st_pages / 10;
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 alloc: if ((ret = __db_shalloc(infop, len, 0, &p)) == 0) {
00090 if (mfp != NULL)
00091 c_mp->stat.st_pages++;
00092 MPOOL_REGION_UNLOCK(dbenv, infop);
00093
00094 found: if (offsetp != NULL)
00095 *offsetp = R_OFFSET(infop, p);
00096 *(void **)retp = p;
00097
00098
00099
00100
00101
00102
00103
00104 total_buckets += buckets;
00105 if (total_buckets != 0) {
00106 if (total_buckets > c_mp->stat.st_alloc_max_buckets)
00107 c_mp->stat.st_alloc_max_buckets = total_buckets;
00108 c_mp->stat.st_alloc_buckets += total_buckets;
00109 }
00110 if (buffers != 0) {
00111 if (buffers > c_mp->stat.st_alloc_max_pages)
00112 c_mp->stat.st_alloc_max_pages = buffers;
00113 c_mp->stat.st_alloc_pages += buffers;
00114 }
00115 return (0);
00116 } else if (giveup || c_mp->stat.st_pages == 0) {
00117 MPOOL_REGION_UNLOCK(dbenv, infop);
00118
00119 __db_err(dbenv,
00120 "unable to allocate space from the buffer cache");
00121 return (ret);
00122 }
00123 ret = 0;
00124
00125
00126
00127
00128
00129 freed_space = 0;
00130 total_buckets += buckets;
00131 buckets = 0;
00132
00133
00134
00135
00136
00137
00138 for (;;) {
00139
00140 if (c_mp->stat.st_pages == 0)
00141 goto alloc;
00142
00143
00144 hp = &dbht[c_mp->last_checked++];
00145 if (hp >= hp_end) {
00146 c_mp->last_checked = 0;
00147 hp = &dbht[c_mp->last_checked++];
00148 }
00149
00150
00151
00152
00153
00154
00155
00156 if (SH_TAILQ_FIRST(&hp->hash_bucket, __bh) == NULL)
00157 continue;
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 if ((++buckets % c_mp->htab_buckets) == 0) {
00190 if (freed_space > 0)
00191 goto alloc;
00192 MPOOL_REGION_UNLOCK(dbenv, infop);
00193
00194 switch (++aggressive) {
00195 case 1:
00196 break;
00197 case 2:
00198 put_counter = c_mp->put_counter;
00199
00200 case 3:
00201 case 4:
00202 case 5:
00203 case 6:
00204 (void)__memp_sync_int(
00205 dbenv, NULL, 0, DB_SYNC_ALLOC, NULL);
00206
00207 __os_sleep(dbenv, 1, 0);
00208 break;
00209 default:
00210 aggressive = 1;
00211 if (put_counter == c_mp->put_counter)
00212 giveup = 1;
00213 break;
00214 }
00215
00216 MPOOL_REGION_LOCK(dbenv, infop);
00217 goto alloc;
00218 }
00219
00220 if (!aggressive) {
00221
00222 if (hp->hash_priority > high_priority)
00223 continue;
00224
00225
00226
00227
00228
00229
00230
00231 if (hp_tmp == NULL) {
00232 hp_tmp = hp;
00233 continue;
00234 }
00235 if (hp->hash_priority > hp_tmp->hash_priority)
00236 hp = hp_tmp;
00237 hp_tmp = NULL;
00238 }
00239
00240
00241 priority = hp->hash_priority;
00242
00243
00244 MPOOL_REGION_UNLOCK(dbenv, infop);
00245 mutex = hp->mtx_hash;
00246 MUTEX_LOCK(dbenv, mutex);
00247
00248 #ifdef DIAGNOSTIC
00249 __memp_check_order(hp);
00250 #endif
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 if ((bhp = SH_TAILQ_FIRST(&hp->hash_bucket, __bh)) == NULL ||
00261 bhp->ref != 0 || bhp->priority > priority)
00262 goto next_hb;
00263
00264 buffers++;
00265
00266
00267 bh_mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset);
00268
00269
00270 ret = 0;
00271 if (F_ISSET(bhp, BH_DIRTY)) {
00272 ++bhp->ref;
00273 ret = __memp_bhwrite(dbmp, hp, bh_mfp, bhp, 0);
00274 --bhp->ref;
00275 if (ret == 0)
00276 ++c_mp->stat.st_rw_evict;
00277 } else
00278 ++c_mp->stat.st_ro_evict;
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291 if (ret != 0 || bhp->ref != 0) {
00292 if (ret != 0 && aggressive)
00293 __memp_bad_buffer(hp);
00294 goto next_hb;
00295 }
00296
00297
00298
00299
00300
00301
00302 if (mfp != NULL &&
00303 mfp->stat.st_pagesize == bh_mfp->stat.st_pagesize) {
00304 if ((ret = __memp_bhfree(dbmp, hp, bhp, 0)) != 0) {
00305 MUTEX_UNLOCK(dbenv, mutex);
00306 return (ret);
00307 }
00308 p = bhp;
00309 goto found;
00310 }
00311
00312 freed_space += __db_shalloc_sizeof(bhp);
00313 if ((ret =
00314 __memp_bhfree(dbmp, hp, bhp, BH_FREE_FREEMEM)) != 0) {
00315 MUTEX_UNLOCK(dbenv, mutex);
00316 return (ret);
00317 }
00318 if (aggressive > 1)
00319 aggressive = 1;
00320
00321
00322
00323
00324
00325
00326 if (0) {
00327 next_hb: MUTEX_UNLOCK(dbenv, mutex);
00328 }
00329 MPOOL_REGION_LOCK(dbenv, infop);
00330
00331
00332
00333
00334
00335
00336
00337 if (freed_space >= 3 * len)
00338 goto alloc;
00339 }
00340
00341 }
00342
00343
00344
00345
00346
00347 static void
00348 __memp_bad_buffer(hp)
00349 DB_MPOOL_HASH *hp;
00350 {
00351 BH *bhp;
00352 u_int32_t priority;
00353
00354
00355 bhp = SH_TAILQ_FIRST(&hp->hash_bucket, __bh);
00356 SH_TAILQ_REMOVE(&hp->hash_bucket, bhp, hq, __bh);
00357
00358
00359
00360
00361
00362 priority = SH_TAILQ_EMPTY(&hp->hash_bucket) ? bhp->priority :
00363 SH_TAILQ_LASTP(&hp->hash_bucket, hq, __bh)->priority;
00364
00365
00366
00367
00368
00369 bhp->priority = priority;
00370 SH_TAILQ_INSERT_TAIL(&hp->hash_bucket, bhp, hq);
00371
00372
00373 hp->hash_priority = SH_TAILQ_FIRSTP(&hp->hash_bucket, __bh)->priority;
00374 #ifdef DIAGNOSTIC
00375 __memp_check_order(hp);
00376 #endif
00377 }
00378
00379 #ifdef DIAGNOSTIC
00380
00381
00382
00383
00384
00385
00386
00387
00388 void
00389 __memp_check_order(hp)
00390 DB_MPOOL_HASH *hp;
00391 {
00392 BH *bhp;
00393 u_int32_t priority;
00394
00395
00396
00397
00398 if ((bhp = SH_TAILQ_FIRST(&hp->hash_bucket, __bh)) == NULL)
00399 return;
00400
00401 DB_ASSERT(bhp->priority == hp->hash_priority);
00402
00403 for (priority = bhp->priority;
00404 (bhp = SH_TAILQ_NEXT(bhp, hq, __bh)) != NULL;
00405 priority = bhp->priority)
00406 DB_ASSERT(priority <= bhp->priority);
00407 }
00408 #endif