00001
00002
00003
00004
00005
00006
00007 #include "config.h"
00008
00009 #ifndef lint
00010 static const char revid[] = "$Id: mp__sync_8c-source.html,v 1.1 2008/06/08 10:20:52 sebdiaz Exp $";
00011 #endif
00012
00013 #ifndef NO_SYSTEM_INCLUDES
00014 #include <sys/types.h>
00015
00016 #include <errno.h>
00017 #include <stdlib.h>
00018 #endif
00019
00020 #ifdef HAVE_RPC
00021 #include "db_server.h"
00022 #endif
00023
00024 #include "db_int.h"
00025 #include "db_shash.h"
00026 #include "mp.h"
00027
00028 #ifdef HAVE_RPC
00029 #include "gen_client_ext.h"
00030 #include "rpc_client_ext.h"
00031 #endif
00032
00033 static int __bhcmp __P((const void *, const void *));
00034 static int __memp_fsync __P((DB_MPOOLFILE *));
00035 static int __memp_sballoc __P((DB_ENV *, BH ***, u_int32_t *));
00036
00037
00038
00039
00040
00041 int
00042 CDB_memp_sync(dbenv, lsnp)
00043 DB_ENV *dbenv;
00044 DB_LSN *lsnp;
00045 {
00046 BH *bhp, **bharray;
00047 DB_MPOOL *dbmp;
00048 DB_LSN tlsn;
00049 MPOOL *c_mp, *mp;
00050 MPOOLFILE *mfp;
00051 u_int32_t ar_cnt, i, ndirty;
00052 int ret, retry_done, retry_need, wrote;
00053
00054 #ifdef HAVE_RPC
00055 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00056 return (__dbcl_memp_sync(dbenv, lsnp));
00057 #endif
00058
00059 PANIC_CHECK(dbenv);
00060 ENV_REQUIRES_CONFIG(dbenv, dbenv->mp_handle, DB_INIT_MPOOL);
00061
00062 dbmp = dbenv->mp_handle;
00063 mp = dbmp->reginfo[0].primary;
00064
00065 if (!LOGGING_ON(dbenv)) {
00066 CDB___db_err(dbenv, "CDB_memp_sync: requires logging");
00067 return (EINVAL);
00068 }
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 if (lsnp == NULL) {
00079 ZERO_LSN(tlsn);
00080 lsnp = &tlsn;
00081 F_SET(mp, MP_LSN_RETRY);
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 MUTEX_LOCK(&mp->sync_mutex, dbenv->lockfhp);
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 R_LOCK(dbenv, dbmp->reginfo);
00103 if (!IS_ZERO_LSN(*lsnp) &&
00104 !F_ISSET(mp, MP_LSN_RETRY) && CDB_log_compare(lsnp, &mp->lsn) <= 0) {
00105 if (mp->lsn_cnt == 0) {
00106 *lsnp = mp->lsn;
00107 ret = 0;
00108 } else
00109 ret = DB_INCOMPLETE;
00110
00111 R_UNLOCK(dbenv, dbmp->reginfo);
00112 MUTEX_UNLOCK(&mp->sync_mutex);
00113 return (ret);
00114 }
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 if ((ret =
00125 __memp_sballoc(dbenv, &bharray, &ndirty)) != 0 || ndirty == 0) {
00126 MUTEX_UNLOCK(&mp->sync_mutex);
00127 return (ret);
00128 }
00129
00130 retry_done = 0;
00131 retry: retry_need = 0;
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148 mp->lsn = *lsnp;
00149
00150
00151
00152
00153
00154
00155
00156 mp->lsn_cnt = 0;
00157 for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile);
00158 mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile))
00159 mfp->lsn_cnt = 0;
00160 F_CLR(mp, MP_LSN_RETRY);
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 for (ar_cnt = 0, i = 0; i < mp->nreg; ++i) {
00176 c_mp = dbmp->reginfo[i].primary;
00177 for (bhp = SH_TAILQ_FIRST(&c_mp->bhq, __bh);
00178 bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, q, __bh)) {
00179 if (F_ISSET(bhp, BH_DIRTY) || bhp->ref != 0) {
00180 F_SET(bhp, BH_WRITE);
00181
00182 ++mp->lsn_cnt;
00183
00184 mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset);
00185 ++mfp->lsn_cnt;
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198 if (bhp->ref == 0) {
00199 ++bhp->ref;
00200 bharray[ar_cnt] = bhp;
00201
00202 if (++ar_cnt >= ndirty) {
00203 retry_need = 1;
00204 break;
00205 }
00206 }
00207 } else
00208 if (F_ISSET(bhp, BH_WRITE))
00209 F_CLR(bhp, BH_WRITE);
00210 }
00211 if (ar_cnt >= ndirty)
00212 break;
00213 }
00214
00215
00216 if (ar_cnt == 0) {
00217 ret = mp->lsn_cnt ? DB_INCOMPLETE : 0;
00218 goto done;
00219 }
00220
00221 R_UNLOCK(dbenv, dbmp->reginfo);
00222
00223
00224
00225
00226
00227
00228
00229
00230 if (ar_cnt > 1)
00231 qsort(bharray, ar_cnt, sizeof(BH *), __bhcmp);
00232
00233 R_LOCK(dbenv, dbmp->reginfo);
00234
00235
00236 for (i = 0; i < ar_cnt; ++i) {
00237
00238
00239
00240
00241
00242
00243
00244 if (bharray[i]->ref > 1) {
00245 --bharray[i]->ref;
00246 continue;
00247 }
00248
00249
00250 mfp = R_ADDR(dbmp->reginfo, bharray[i]->mf_offset);
00251 ret = CDB___memp_bhwrite(dbmp, mfp, bharray[i], NULL, &wrote);
00252
00253
00254 --bharray[i]->ref;
00255
00256 if (ret == 0 && wrote)
00257 continue;
00258
00259
00260
00261
00262
00263
00264 if (ret == 0) {
00265 CDB___db_err(dbenv, "%s: unable to flush page: %lu",
00266 CDB___memp_fns(dbmp, mfp), (u_long)bharray[i]->pgno);
00267 ret = EPERM;
00268 }
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281 ZERO_LSN(mp->lsn);
00282 F_SET(mp, MP_LSN_RETRY);
00283
00284
00285 while (++i < ar_cnt)
00286 --bharray[i]->ref;
00287
00288 goto done;
00289 }
00290
00291 ret = mp->lsn_cnt != 0 ? DB_INCOMPLETE : 0;
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 if (retry_need) {
00303 if (retry_done) {
00304 ret = DB_INCOMPLETE;
00305 F_SET(mp, MP_LSN_RETRY);
00306 } else {
00307 retry_done = 1;
00308 goto retry;
00309 }
00310 }
00311
00312 done: R_UNLOCK(dbenv, dbmp->reginfo);
00313 MUTEX_UNLOCK(&mp->sync_mutex);
00314
00315 CDB___os_free(bharray, ndirty * sizeof(BH *));
00316
00317 return (ret);
00318 }
00319
00320
00321
00322
00323
00324 int
00325 CDB_memp_fsync(dbmfp)
00326 DB_MPOOLFILE *dbmfp;
00327 {
00328 DB_ENV *dbenv;
00329 DB_MPOOL *dbmp;
00330 int is_tmp;
00331
00332 dbmp = dbmfp->dbmp;
00333 dbenv = dbmp->dbenv;
00334
00335 #ifdef HAVE_RPC
00336 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00337 return (__dbcl_memp_fsync(dbmfp));
00338 #endif
00339
00340 PANIC_CHECK(dbenv);
00341
00342
00343
00344
00345
00346
00347 if (F_ISSET(dbmfp, MP_READONLY))
00348 return (0);
00349
00350 R_LOCK(dbenv, dbmp->reginfo);
00351 is_tmp = F_ISSET(dbmfp->mfp, MP_TEMP);
00352 R_UNLOCK(dbenv, dbmp->reginfo);
00353 if (is_tmp)
00354 return (0);
00355
00356 return (__memp_fsync(dbmfp));
00357 }
00358
00359
00360
00361
00362
00363
00364
00365 int
00366 CDB___mp_xxx_fh(dbmfp, fhp)
00367 DB_MPOOLFILE *dbmfp;
00368 DB_FH **fhp;
00369 {
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 *fhp = &dbmfp->fh;
00385 return (F_ISSET(&dbmfp->fh, DB_FH_VALID) ? 0 : __memp_fsync(dbmfp));
00386 }
00387
00388
00389
00390
00391
00392 static int
00393 __memp_fsync(dbmfp)
00394 DB_MPOOLFILE *dbmfp;
00395 {
00396 BH *bhp, **bharray;
00397 DB_ENV *dbenv;
00398 DB_MPOOL *dbmp;
00399 MPOOL *c_mp, *mp;
00400 size_t mf_offset;
00401 u_int32_t ar_cnt, i, ndirty;
00402 int incomplete, ret, retry_done, retry_need, wrote;
00403
00404 dbmp = dbmfp->dbmp;
00405 dbenv = dbmp->dbenv;
00406 mp = dbmp->reginfo[0].primary;
00407
00408 R_LOCK(dbenv, dbmp->reginfo);
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 if ((ret =
00419 __memp_sballoc(dbenv, &bharray, &ndirty)) != 0 || ndirty == 0)
00420 return (ret);
00421
00422 retry_done = 0;
00423 retry: retry_need = 0;
00424
00425
00426
00427
00428
00429
00430
00431
00432 mf_offset = R_OFFSET(dbmp->reginfo, dbmfp->mfp);
00433 for (ar_cnt = 0, incomplete = 0, i = 0; i < mp->nreg; ++i) {
00434 c_mp = dbmp->reginfo[i].primary;
00435 for (bhp = SH_TAILQ_FIRST(&c_mp->bhq, __bh);
00436 bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, q, __bh)) {
00437 if (!F_ISSET(bhp, BH_DIRTY) ||
00438 bhp->mf_offset != mf_offset)
00439 continue;
00440 if (bhp->ref != 0 || F_ISSET(bhp, BH_LOCKED)) {
00441 incomplete = 1;
00442 continue;
00443 }
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456 ++bhp->ref;
00457 bharray[ar_cnt] = bhp;
00458 if (++ar_cnt >= ndirty) {
00459 retry_need = 1;
00460 break;
00461 }
00462 }
00463 if (ar_cnt >= ndirty)
00464 break;
00465 }
00466
00467
00468 if (ar_cnt == 0) {
00469 ret = 0;
00470 goto done;
00471 }
00472
00473 R_UNLOCK(dbenv, dbmp->reginfo);
00474
00475
00476 if (ar_cnt > 1)
00477 qsort(bharray, ar_cnt, sizeof(BH *), __bhcmp);
00478
00479 R_LOCK(dbenv, dbmp->reginfo);
00480
00481
00482 for (i = 0; i < ar_cnt;) {
00483
00484
00485
00486
00487
00488
00489
00490 if (bharray[i]->ref > 1) {
00491 incomplete = 1;
00492 --bharray[i++]->ref;
00493 continue;
00494 }
00495
00496
00497 ret = CDB___memp_pgwrite(dbmp, dbmfp, bharray[i], NULL, &wrote);
00498
00499
00500 --bharray[i++]->ref;
00501
00502 if (ret == 0) {
00503 if (!wrote)
00504 incomplete = 1;
00505 continue;
00506 }
00507
00508
00509
00510
00511
00512
00513 while (i < ar_cnt)
00514 --bharray[i++]->ref;
00515 break;
00516 }
00517
00518
00519
00520
00521
00522
00523
00524
00525 if (retry_need) {
00526 if (retry_done)
00527 incomplete = 1;
00528 else {
00529 retry_done = 1;
00530 goto retry;
00531 }
00532 }
00533
00534 done: R_UNLOCK(dbenv, dbmp->reginfo);
00535
00536 CDB___os_free(bharray, ndirty * sizeof(BH *));
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546 if (ret == 0)
00547 ret = incomplete ?
00548 DB_INCOMPLETE : CDB___os_fsync(dbenv, &dbmfp->fh);
00549
00550 return (ret);
00551 }
00552
00553
00554
00555
00556
00557 static int
00558 __memp_sballoc(dbenv, bharrayp, ndirtyp)
00559 DB_ENV *dbenv;
00560 BH ***bharrayp;
00561 u_int32_t *ndirtyp;
00562 {
00563 DB_MPOOL *dbmp;
00564 MPOOL *c_mp, *mp;
00565 u_int32_t i, nclean, ndirty, maxpin;
00566 int ret;
00567
00568 dbmp = dbenv->mp_handle;
00569 mp = dbmp->reginfo[0].primary;
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581 for (nclean = ndirty = 0, i = 0; i < mp->nreg; ++i) {
00582 c_mp = dbmp->reginfo[i].primary;
00583 ndirty += c_mp->stat.st_page_dirty;
00584 nclean += c_mp->stat.st_page_clean;
00585 }
00586 R_UNLOCK(dbenv, dbmp->reginfo);
00587 if (ndirty == 0) {
00588 *ndirtyp = 0;
00589 return (0);
00590 }
00591
00592
00593
00594
00595
00596
00597
00598 maxpin = ((ndirty + nclean) * 8) / 10;
00599 if (maxpin < 10)
00600 maxpin = 10;
00601
00602
00603
00604
00605
00606
00607 ndirty += ndirty / 2 + 10;
00608 if (ndirty > maxpin)
00609 ndirty = maxpin;
00610 if ((ret =
00611 CDB___os_malloc(dbenv, ndirty * sizeof(BH *), NULL, bharrayp)) != 0)
00612 return (ret);
00613
00614 *ndirtyp = ndirty;
00615
00616 R_LOCK(dbenv, dbmp->reginfo);
00617
00618 return (0);
00619 }
00620
00621 static int
00622 __bhcmp(p1, p2)
00623 const void *p1, *p2;
00624 {
00625 BH *bhp1, *bhp2;
00626
00627 bhp1 = *(BH * const *)p1;
00628 bhp2 = *(BH * const *)p2;
00629
00630
00631 if (bhp1->mf_offset < bhp2->mf_offset)
00632 return (-1);
00633 if (bhp1->mf_offset > bhp2->mf_offset)
00634 return (1);
00635
00636
00637
00638
00639
00640
00641 if (bhp1->pgno < bhp2->pgno)
00642 return (-1);
00643 if (bhp1->pgno > bhp2->pgno)
00644 return (1);
00645 return (0);
00646 }