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
00015 #ifdef HAVE_RPC
00016 #include <rpc/rpc.h>
00017 #endif
00018
00019 #include <string.h>
00020 #endif
00021
00022 #ifdef HAVE_RPC
00023 #include "db_server.h"
00024 #endif
00025
00026 #include "db_int.h"
00027 #include "dbinc/db_page.h"
00028 #include "dbinc/db_shash.h"
00029 #include "dbinc/db_am.h"
00030 #include "dbinc/lock.h"
00031 #include "dbinc/mp.h"
00032 #include "dbinc/txn.h"
00033 #include "dbinc_auto/sequence_ext.h"
00034
00035 #ifdef HAVE_RPC
00036 #include "dbinc_auto/rpc_client_ext.h"
00037 #endif
00038
00039 #ifdef HAVE_SEQUENCE
00040 #define SEQ_ILLEGAL_AFTER_OPEN(seq, name) \
00041 if (seq->seq_key.data != NULL) \
00042 return (__db_mi_open((seq)->seq_dbp->dbenv, name, 1));
00043
00044 #define SEQ_ILLEGAL_BEFORE_OPEN(seq, name) \
00045 if (seq->seq_key.data == NULL) \
00046 return (__db_mi_open((seq)->seq_dbp->dbenv, name, 0));
00047
00048 #define SEQ_IS_OPEN(seq) ((seq)->seq_key.data != NULL)
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 #define SEQ_SWAP(rp) \
00061 do { \
00062 M_32_SWAP((rp)->seq_version); \
00063 M_32_SWAP((rp)->flags); \
00064 M_64_SWAP((rp)->seq_value); \
00065 M_64_SWAP((rp)->seq_max); \
00066 M_64_SWAP((rp)->seq_min); \
00067 } while (0)
00068
00069 #define SEQ_SWAP_IN(seq) \
00070 do { \
00071 if (__db_isbigendian()) { \
00072 memcpy(&seq->seq_record, seq->seq_data.data, \
00073 sizeof(seq->seq_record)); \
00074 SEQ_SWAP(&seq->seq_record); \
00075 } \
00076 } while (0)
00077
00078 #define SEQ_SWAP_OUT(seq) \
00079 do { \
00080 if (__db_isbigendian()) { \
00081 memcpy(seq->seq_data.data, \
00082 &seq->seq_record, sizeof(seq->seq_record));\
00083 SEQ_SWAP((DB_SEQ_RECORD*)seq->seq_data.data); \
00084 } \
00085 } while (0)
00086
00087 static int __seq_chk_cachesize __P((DB_ENV *, int32_t, db_seq_t, db_seq_t));
00088 static int __seq_close __P((DB_SEQUENCE *, u_int32_t));
00089 static int __seq_get
00090 __P((DB_SEQUENCE *, DB_TXN *, int32_t, db_seq_t *, u_int32_t));
00091 static int __seq_get_cachesize __P((DB_SEQUENCE *, int32_t *));
00092 static int __seq_get_db __P((DB_SEQUENCE *, DB **));
00093 static int __seq_get_flags __P((DB_SEQUENCE *, u_int32_t *));
00094 static int __seq_get_key __P((DB_SEQUENCE *, DBT *));
00095 static int __seq_get_range __P((DB_SEQUENCE *, db_seq_t *, db_seq_t *));
00096 static int __seq_initial_value __P((DB_SEQUENCE *, db_seq_t));
00097 static int __seq_open_pp __P((DB_SEQUENCE *, DB_TXN *, DBT *, u_int32_t));
00098 static int __seq_remove __P((DB_SEQUENCE *, DB_TXN *, u_int32_t));
00099 static int __seq_set_cachesize __P((DB_SEQUENCE *, int32_t));
00100 static int __seq_set_flags __P((DB_SEQUENCE *, u_int32_t));
00101 static int __seq_set_range __P((DB_SEQUENCE *, db_seq_t, db_seq_t));
00102 static int __seq_update __P((DB_SEQUENCE *, DB_TXN *, int32_t, u_int32_t));
00103
00104
00105
00106
00107
00108
00109
00110 int
00111 db_sequence_create(seqp, dbp, flags)
00112 DB_SEQUENCE **seqp;
00113 DB *dbp;
00114 u_int32_t flags;
00115 {
00116 DB_ENV *dbenv;
00117 DB_SEQUENCE *seq;
00118 int ret;
00119
00120 dbenv = dbp->dbenv;
00121
00122 DB_ILLEGAL_BEFORE_OPEN(dbp, "db_sequence_create");
00123 #ifdef HAVE_RPC
00124 if (RPC_ON(dbenv))
00125 return (__dbcl_dbenv_illegal(dbenv));
00126 #endif
00127
00128
00129 switch (flags) {
00130 case 0:
00131 break;
00132 default:
00133 return (__db_ferr(dbenv, "db_sequence_create", 0));
00134 }
00135
00136
00137 if ((ret = __os_calloc(dbenv, 1, sizeof(*seq), &seq)) != 0)
00138 return (ret);
00139
00140 seq->seq_dbp = dbp;
00141 seq->close = __seq_close;
00142 seq->get = __seq_get;
00143 seq->get_cachesize = __seq_get_cachesize;
00144 seq->set_cachesize = __seq_set_cachesize;
00145 seq->get_db = __seq_get_db;
00146 seq->get_flags = __seq_get_flags;
00147 seq->get_key = __seq_get_key;
00148 seq->get_range = __seq_get_range;
00149 seq->initial_value = __seq_initial_value;
00150 seq->open = __seq_open_pp;
00151 seq->remove = __seq_remove;
00152 seq->set_flags = __seq_set_flags;
00153 seq->set_range = __seq_set_range;
00154 seq->stat = __seq_stat;
00155 seq->stat_print = __seq_stat_print;
00156 seq->seq_rp = &seq->seq_record;
00157 *seqp = seq;
00158
00159 return (0);
00160 }
00161
00162
00163
00164
00165
00166
00167 static int
00168 __seq_open_pp(seq, txn, keyp, flags)
00169 DB_SEQUENCE *seq;
00170 DB_TXN *txn;
00171 DBT *keyp;
00172 u_int32_t flags;
00173 {
00174 DB *dbp;
00175 DB_ENV *dbenv;
00176 DB_SEQ_RECORD *rp;
00177 DB_THREAD_INFO *ip;
00178 u_int32_t tflags;
00179 int handle_check, txn_local, ret, t_ret;
00180 #define SEQ_OPEN_FLAGS (DB_CREATE | DB_EXCL | DB_THREAD)
00181
00182 dbp = seq->seq_dbp;
00183 dbenv = dbp->dbenv;
00184 txn_local = 0;
00185
00186 STRIP_AUTO_COMMIT(flags);
00187 SEQ_ILLEGAL_AFTER_OPEN(seq, "DB_SEQUENCE->open");
00188
00189 ENV_ENTER(dbenv, ip);
00190
00191
00192 handle_check = IS_ENV_REPLICATED(dbenv);
00193 if (handle_check &&
00194 (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
00195 handle_check = 0;
00196 goto err;
00197 }
00198
00199 if ((ret = __db_fchk(dbenv,
00200 "DB_SEQUENCE->open", flags, SEQ_OPEN_FLAGS)) != 0)
00201 goto err;
00202
00203 if (keyp->size == 0) {
00204 __db_err(dbenv, "Zero length sequence key specified");
00205 goto err;
00206 }
00207
00208 if ((ret = __db_get_flags(dbp, &tflags)) != 0)
00209 goto err;
00210
00211 if (FLD_ISSET(tflags, DB_DUP)) {
00212 __db_err(dbenv,
00213 "Sequences not supported in databases configured for duplicate data");
00214 goto err;
00215 }
00216
00217 if (LF_ISSET(DB_THREAD)) {
00218 if (RPC_ON(dbenv)) {
00219 __db_err(dbenv,
00220 "DB_SEQUENCE->open: DB_THREAD not supported with RPC");
00221 goto err;
00222 }
00223 if ((ret = __mutex_alloc(dbenv,
00224 MTX_SEQUENCE, DB_MUTEX_THREAD, &seq->mtx_seq)) != 0)
00225 goto err;
00226 }
00227
00228 memset(&seq->seq_data, 0, sizeof(DBT));
00229 if (__db_isbigendian()) {
00230 if ((ret = __os_umalloc(dbenv,
00231 sizeof(seq->seq_record), &seq->seq_data.data)) != 0)
00232 goto err;
00233 seq->seq_data.flags = DB_DBT_REALLOC;
00234 } else {
00235 seq->seq_data.data = &seq->seq_record;
00236 seq->seq_data.flags = DB_DBT_USERMEM;
00237 }
00238
00239 seq->seq_data.ulen = seq->seq_data.size = sizeof(seq->seq_record);
00240 seq->seq_rp = &seq->seq_record;
00241
00242 memset(&seq->seq_key, 0, sizeof(DBT));
00243 if ((ret = __os_malloc(dbenv, keyp->size, &seq->seq_key.data)) != 0)
00244 goto err;
00245 memcpy(seq->seq_key.data, keyp->data, keyp->size);
00246 seq->seq_key.size = seq->seq_key.ulen = keyp->size;
00247 seq->seq_key.flags = DB_DBT_USERMEM;
00248
00249 retry: if ((ret = __db_get(dbp, txn, &seq->seq_key, &seq->seq_data, 0)) != 0) {
00250 if (ret == DB_BUFFER_SMALL &&
00251 seq->seq_data.size > sizeof(seq->seq_record)) {
00252 seq->seq_data.flags = DB_DBT_REALLOC;
00253 seq->seq_data.data = NULL;
00254 goto retry;
00255 }
00256 if ((ret != DB_NOTFOUND && ret != DB_KEYEMPTY) ||
00257 !LF_ISSET(DB_CREATE))
00258 goto err;
00259 ret = 0;
00260
00261 rp = &seq->seq_record;
00262 if (!F_ISSET(rp, DB_SEQ_RANGE_SET)) {
00263 rp->seq_max = INT64_MAX;
00264 rp->seq_min = INT64_MIN;
00265 }
00266
00267 if (!F_ISSET(rp, DB_SEQ_DEC))
00268 F_SET(rp, DB_SEQ_INC);
00269
00270 rp->seq_version = DB_SEQUENCE_VERSION;
00271
00272 if (rp->seq_value > rp->seq_max ||
00273 rp->seq_value < rp->seq_min) {
00274 __db_err(dbenv, "Sequence value out of range");
00275 ret = EINVAL;
00276 goto err;
00277 } else {
00278 SEQ_SWAP_OUT(seq);
00279 if ((ret = __db_put(dbp, txn, &seq->seq_key,
00280 &seq->seq_data, DB_NOOVERWRITE)) != 0) {
00281 __db_err(dbenv, "Sequence create failed");
00282 goto err;
00283 }
00284 }
00285 } else if (LF_ISSET(DB_CREATE) && LF_ISSET(DB_EXCL)) {
00286 ret = EEXIST;
00287 goto err;
00288 } else if (seq->seq_data.size < sizeof(seq->seq_record)) {
00289 __db_err(dbenv, "Bad sequence record format");
00290 ret = EINVAL;
00291 goto err;
00292 }
00293
00294 if (!__db_isbigendian())
00295 seq->seq_rp = seq->seq_data.data;
00296
00297
00298
00299
00300
00301 rp = seq->seq_data.data;
00302 if (rp->seq_version == DB_SEQUENCE_OLDVER) {
00303 oldver: rp->seq_version = DB_SEQUENCE_VERSION;
00304 if (__db_isbigendian()) {
00305 if (IS_DB_AUTO_COMMIT(dbp, txn)) {
00306 if ((ret =
00307 __txn_begin(dbenv, NULL, &txn, 0)) != 0)
00308 goto err;
00309 txn_local = 1;
00310 goto retry;
00311 }
00312 memcpy(&seq->seq_record, rp, sizeof(seq->seq_record));
00313 SEQ_SWAP_OUT(seq);
00314 }
00315 if ((ret = __db_put(dbp,
00316 txn, &seq->seq_key, &seq->seq_data, 0)) != 0)
00317 goto err;
00318 }
00319 rp = seq->seq_rp;
00320
00321 SEQ_SWAP_IN(seq);
00322
00323 if (rp->seq_version != DB_SEQUENCE_VERSION) {
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 if (rp->seq_version == DB_SEQUENCE_OLDVER)
00334 goto oldver;
00335 M_32_SWAP(rp->seq_version);
00336 if (rp->seq_version == DB_SEQUENCE_OLDVER) {
00337 SEQ_SWAP(rp);
00338 goto oldver;
00339 }
00340 M_32_SWAP(rp->seq_version);
00341 __db_err(dbenv,
00342 "Unsupported sequence version: %d", rp->seq_version);
00343 goto err;
00344 }
00345
00346 seq->seq_last_value = rp->seq_value;
00347 if (F_ISSET(rp, DB_SEQ_INC))
00348 seq->seq_last_value--;
00349 else
00350 seq->seq_last_value++;
00351
00352
00353
00354
00355 if (seq->seq_cache_size != 0 && (ret = __seq_chk_cachesize(
00356 dbenv, seq->seq_cache_size, rp->seq_max, rp->seq_min)) != 0)
00357 goto err;
00358
00359 err: if (txn_local &&
00360 (t_ret = __db_txn_auto_resolve(dbenv, txn, 0, ret)) && ret == 0)
00361 ret = t_ret;
00362 if (ret != 0) {
00363 __os_free(dbenv, seq->seq_key.data);
00364 seq->seq_key.data = NULL;
00365 }
00366
00367 if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00368 ret = t_ret;
00369
00370 ENV_LEAVE(dbenv, ip);
00371 return (ret);
00372 }
00373
00374
00375
00376
00377
00378
00379 static int
00380 __seq_get_cachesize(seq, cachesize)
00381 DB_SEQUENCE *seq;
00382 int32_t *cachesize;
00383 {
00384 SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get_cachesize");
00385
00386 *cachesize = seq->seq_cache_size;
00387 return (0);
00388 }
00389
00390
00391
00392
00393
00394
00395 static int
00396 __seq_set_cachesize(seq, cachesize)
00397 DB_SEQUENCE *seq;
00398 int32_t cachesize;
00399 {
00400 DB_ENV *dbenv;
00401 int ret;
00402
00403 dbenv = seq->seq_dbp->dbenv;
00404
00405 if (cachesize < 0) {
00406 __db_err(dbenv, "Cache size must be >= 0");
00407 return (EINVAL);
00408 }
00409
00410
00411
00412
00413 if (SEQ_IS_OPEN(seq) && (ret = __seq_chk_cachesize(dbenv,
00414 cachesize, seq->seq_rp->seq_max, seq->seq_rp->seq_min)) != 0)
00415 return (ret);
00416
00417 seq->seq_cache_size = cachesize;
00418 return (0);
00419 }
00420
00421 #define SEQ_SET_FLAGS (DB_SEQ_WRAP | DB_SEQ_INC | DB_SEQ_DEC)
00422
00423
00424
00425
00426
00427 static int
00428 __seq_get_flags(seq, flagsp)
00429 DB_SEQUENCE *seq;
00430 u_int32_t *flagsp;
00431 {
00432 SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get_flags");
00433
00434 *flagsp = F_ISSET(seq->seq_rp, SEQ_SET_FLAGS);
00435 return (0);
00436 }
00437
00438
00439
00440
00441
00442
00443 static int
00444 __seq_set_flags(seq, flags)
00445 DB_SEQUENCE *seq;
00446 u_int32_t flags;
00447 {
00448 DB_ENV *dbenv;
00449 DB_SEQ_RECORD *rp;
00450 int ret;
00451
00452 dbenv = seq->seq_dbp->dbenv;
00453 rp = seq->seq_rp;
00454
00455 SEQ_ILLEGAL_AFTER_OPEN(seq, "DB_SEQUENCE->set_flags");
00456
00457 if ((ret = __db_fchk(
00458 dbenv, "DB_SEQUENCE->set_flags", flags, SEQ_SET_FLAGS)) != 0)
00459 return (ret);
00460 if ((ret = __db_fcchk(dbenv,
00461 "DB_SEQUENCE->set_flags", flags, DB_SEQ_DEC, DB_SEQ_INC)) != 0)
00462 return (ret);
00463
00464 if (LF_ISSET(DB_SEQ_DEC | DB_SEQ_INC))
00465 F_CLR(rp, DB_SEQ_DEC | DB_SEQ_INC);
00466 F_SET(rp, flags);
00467
00468 return (0);
00469 }
00470
00471
00472
00473
00474
00475
00476 static int
00477 __seq_initial_value(seq, value)
00478 DB_SEQUENCE *seq;
00479 db_seq_t value;
00480 {
00481 DB_ENV *dbenv;
00482 DB_SEQ_RECORD *rp;
00483
00484 dbenv = seq->seq_dbp->dbenv;
00485 SEQ_ILLEGAL_AFTER_OPEN(seq, "DB_SEQUENCE->initial_value");
00486
00487 rp = seq->seq_rp;
00488 if (F_ISSET(rp, DB_SEQ_RANGE_SET) &&
00489 (value > rp->seq_max || value < rp->seq_min)) {
00490 __db_err(dbenv, "Sequence value out of range");
00491 return (EINVAL);
00492 }
00493
00494 rp->seq_value = value;
00495
00496 return (0);
00497 }
00498
00499
00500
00501
00502
00503
00504 static int
00505 __seq_get_range(seq, minp, maxp)
00506 DB_SEQUENCE *seq;
00507 db_seq_t *minp, *maxp;
00508 {
00509 SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get_range");
00510
00511 *minp = seq->seq_rp->seq_min;
00512 *maxp = seq->seq_rp->seq_max;
00513 return (0);
00514 }
00515
00516
00517
00518
00519
00520
00521 static int
00522 __seq_set_range(seq, min, max)
00523 DB_SEQUENCE *seq;
00524 db_seq_t min, max;
00525 {
00526 DB_ENV *dbenv;
00527
00528 dbenv = seq->seq_dbp->dbenv;
00529 SEQ_ILLEGAL_AFTER_OPEN(seq, "DB_SEQUENCE->set_range");
00530
00531 if (min >= max) {
00532 __db_err(dbenv,
00533 "Minimum sequence value must be less than maximum sequence value");
00534 return (EINVAL);
00535 }
00536
00537 seq->seq_rp->seq_min = min;
00538 seq->seq_rp->seq_max = max;
00539 F_SET(seq->seq_rp, DB_SEQ_RANGE_SET);
00540
00541 return (0);
00542 }
00543
00544 static int
00545 __seq_update(seq, txn, delta, flags)
00546 DB_SEQUENCE *seq;
00547 DB_TXN *txn;
00548 int32_t delta;
00549 u_int32_t flags;
00550 {
00551 DB *dbp;
00552 DB_ENV *dbenv;
00553 DB_SEQ_RECORD *rp;
00554 int32_t adjust;
00555 int ret, txn_local;
00556
00557 dbp = seq->seq_dbp;
00558 dbenv = dbp->dbenv;
00559
00560
00561
00562
00563
00564
00565 if (IS_DB_AUTO_COMMIT(dbp, txn)) {
00566 if ((ret = __txn_begin(dbenv, NULL, &txn, 0)) != 0)
00567 return (ret);
00568 txn_local = 1;
00569 } else
00570 txn_local = 0;
00571
00572
00573 if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
00574 goto err;
00575
00576 retry: if ((ret = __db_get(dbp, txn, &seq->seq_key, &seq->seq_data, 0)) != 0) {
00577 if (ret == DB_BUFFER_SMALL &&
00578 seq->seq_data.size > sizeof(seq->seq_record)) {
00579 seq->seq_data.flags = DB_DBT_REALLOC;
00580 seq->seq_data.data = NULL;
00581 goto retry;
00582 }
00583 goto err;
00584 }
00585
00586 if (!__db_isbigendian())
00587 seq->seq_rp = seq->seq_data.data;
00588 SEQ_SWAP_IN(seq);
00589 rp = seq->seq_rp;
00590
00591 if (F_ISSET(rp, DB_SEQ_WRAPPED))
00592 goto overflow;
00593
00594 if (seq->seq_data.size < sizeof(seq->seq_record)) {
00595 __db_err(dbenv, "Bad sequence record format");
00596 ret = EINVAL;
00597 goto err;
00598 }
00599
00600 adjust = delta > seq->seq_cache_size ? delta : seq->seq_cache_size;
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611 again: if (F_ISSET(rp, DB_SEQ_INC)) {
00612 if (rp->seq_value + adjust - 1 < rp->seq_value ||
00613 rp->seq_value + adjust - 1 > rp->seq_max) {
00614
00615 if (adjust > delta) {
00616 adjust = delta;
00617 goto again;
00618 }
00619 if (F_ISSET(rp, DB_SEQ_WRAP))
00620 rp->seq_value = rp->seq_min;
00621 else {
00622 overflow: __db_err(dbenv, "Sequence overflow");
00623 ret = EINVAL;
00624 goto err;
00625 }
00626 }
00627
00628 if (!F_ISSET(rp, DB_SEQ_WRAP) &&
00629 rp->seq_value + adjust < rp->seq_value)
00630 F_SET(rp, DB_SEQ_WRAPPED);
00631 } else {
00632 if ((rp->seq_value - adjust) + 1 > rp->seq_value ||
00633 (rp->seq_value - adjust) + 1 < rp->seq_min) {
00634
00635 if (adjust > delta) {
00636 adjust = delta;
00637 goto again;
00638 }
00639 if (F_ISSET(rp, DB_SEQ_WRAP))
00640 rp->seq_value = rp->seq_max;
00641 else
00642 goto overflow;
00643 }
00644
00645 if (!F_ISSET(rp, DB_SEQ_WRAP) &&
00646 rp->seq_value - adjust > rp->seq_value)
00647 F_SET(rp, DB_SEQ_WRAPPED);
00648 adjust = -adjust;
00649 }
00650
00651 rp->seq_value += adjust;
00652 SEQ_SWAP_OUT(seq);
00653 ret = __db_put(dbp, txn, &seq->seq_key, &seq->seq_data, 0);
00654 rp->seq_value -= adjust;
00655 if (ret != 0) {
00656 __db_err(dbenv, "Sequence update failed");
00657 goto err;
00658 }
00659 seq->seq_last_value = rp->seq_value + adjust;
00660 if (F_ISSET(rp, DB_SEQ_INC))
00661 seq->seq_last_value--;
00662 else
00663 seq->seq_last_value++;
00664
00665 err: return (txn_local ? __db_txn_auto_resolve(
00666 dbenv, txn, LF_ISSET(DB_TXN_NOSYNC), ret) : ret);
00667 }
00668
00669 static int
00670 __seq_get(seq, txn, delta, retp, flags)
00671 DB_SEQUENCE *seq;
00672 DB_TXN *txn;
00673 int32_t delta;
00674 db_seq_t *retp;
00675 u_int32_t flags;
00676 {
00677 DB *dbp;
00678 DB_ENV *dbenv;
00679 DB_SEQ_RECORD *rp;
00680 DB_THREAD_INFO *ip;
00681 int handle_check, ret, t_ret;
00682
00683 dbp = seq->seq_dbp;
00684 dbenv = dbp->dbenv;
00685 rp = seq->seq_rp;
00686 ret = 0;
00687
00688 STRIP_AUTO_COMMIT(flags);
00689 SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get");
00690
00691 if (delta <= 0) {
00692 __db_err(dbenv, "Sequence delta must be greater than 0");
00693 return (EINVAL);
00694 }
00695
00696 if (seq->seq_cache_size != 0 && txn != NULL) {
00697 __db_err(dbenv,
00698 "Sequence with non-zero cache may not specify transaction handle");
00699 return (EINVAL);
00700 }
00701
00702 ENV_ENTER(dbenv, ip);
00703
00704
00705 handle_check = IS_ENV_REPLICATED(dbenv);
00706 if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0)
00707 return (ret);
00708
00709 MUTEX_LOCK(dbenv, seq->mtx_seq);
00710
00711 if (rp->seq_min + delta > rp->seq_max) {
00712 __db_err(dbenv, "Sequence overflow");
00713 ret = EINVAL;
00714 goto err;
00715 }
00716
00717 if (F_ISSET(rp, DB_SEQ_INC)) {
00718 if (seq->seq_last_value + 1 - rp->seq_value < delta &&
00719 (ret = __seq_update(seq, txn, delta, flags)) != 0)
00720 goto err;
00721
00722 rp = seq->seq_rp;
00723 *retp = rp->seq_value;
00724 rp->seq_value += delta;
00725 } else {
00726 if ((rp->seq_value - seq->seq_last_value) + 1 < delta &&
00727 (ret = __seq_update(seq, txn, delta, flags)) != 0)
00728 goto err;
00729
00730 rp = seq->seq_rp;
00731 *retp = rp->seq_value;
00732 rp->seq_value -= delta;
00733 }
00734
00735 err: MUTEX_UNLOCK(dbenv, seq->mtx_seq);
00736
00737
00738 if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00739 ret = t_ret;
00740
00741 ENV_LEAVE(dbenv, ip);
00742 return (ret);
00743 }
00744
00745
00746
00747
00748
00749
00750 static int
00751 __seq_get_db(seq, dbpp)
00752 DB_SEQUENCE *seq;
00753 DB **dbpp;
00754 {
00755 SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get_db");
00756
00757 *dbpp = seq->seq_dbp;
00758 return (0);
00759 }
00760
00761
00762
00763
00764
00765
00766 static int
00767 __seq_get_key(seq, key)
00768 DB_SEQUENCE *seq;
00769 DBT *key;
00770 {
00771 SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get_key");
00772
00773 key->data = seq->seq_key.data;
00774 key->size = key->ulen = seq->seq_key.size;
00775 key->flags = seq->seq_key.flags;
00776 return (0);
00777 }
00778
00779
00780
00781
00782
00783
00784 static int
00785 __seq_close(seq, flags)
00786 DB_SEQUENCE *seq;
00787 u_int32_t flags;
00788 {
00789 DB_ENV *dbenv;
00790 int ret, t_ret;
00791
00792 ret = 0;
00793 dbenv = seq->seq_dbp->dbenv;
00794
00795 if (flags != 0)
00796 ret = __db_ferr(dbenv, "DB_SEQUENCE->close", 0);
00797
00798 if ((t_ret = __mutex_free(dbenv, &seq->mtx_seq)) != 0 && ret == 0)
00799 ret = t_ret;
00800
00801 if (seq->seq_key.data != NULL)
00802 __os_free(dbenv, seq->seq_key.data);
00803 if (seq->seq_data.data != NULL &&
00804 seq->seq_data.data != &seq->seq_record)
00805 __os_ufree(dbenv, seq->seq_data.data);
00806 seq->seq_key.data = NULL;
00807
00808 memset(seq, CLEAR_BYTE, sizeof(*seq));
00809 __os_free(dbenv, seq);
00810
00811 return (ret);
00812 }
00813
00814
00815
00816
00817
00818 static int
00819 __seq_remove(seq, txn, flags)
00820 DB_SEQUENCE *seq;
00821 DB_TXN *txn;
00822 u_int32_t flags;
00823 {
00824 DB *dbp;
00825 DB_ENV *dbenv;
00826 DB_THREAD_INFO *ip;
00827 int handle_check, ret, t_ret;
00828
00829 dbp = seq->seq_dbp;
00830 dbenv = dbp->dbenv;
00831
00832 SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->remove");
00833 ENV_ENTER(dbenv, ip);
00834
00835
00836 handle_check = IS_ENV_REPLICATED(dbenv);
00837 if (handle_check &&
00838 (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
00839 handle_check = 0;
00840 goto err;
00841 }
00842 if (flags != 0)
00843 ret = __db_ferr(dbenv, "DB_SEQUENCE->remove", 0);
00844
00845 ret = __db_del(dbp, txn, &seq->seq_key, 0);
00846
00847 if ((t_ret = __seq_close(seq, 0)) != 0 && ret == 0)
00848 ret = t_ret;
00849
00850
00851 if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00852 ret = t_ret;
00853 err: ENV_LEAVE(dbenv, ip);
00854 return (ret);
00855 }
00856
00857
00858
00859
00860
00861 static int
00862 __seq_chk_cachesize(dbenv, cachesize, max, min)
00863 DB_ENV *dbenv;
00864 int32_t cachesize;
00865 db_seq_t max, min;
00866 {
00867
00868
00869
00870
00871
00872
00873
00874 if ((u_int32_t)cachesize > (u_int64_t)max - (u_int64_t)min) {
00875 __db_err(dbenv,
00876 "Number of items to be cached is larger than the sequence range");
00877 return (EINVAL);
00878 }
00879 return (0);
00880 }
00881
00882 #else
00883
00884 int
00885 db_sequence_create(seqp, dbp, flags)
00886 DB_SEQUENCE **seqp;
00887 DB *dbp;
00888 u_int32_t flags;
00889 {
00890 COMPQUIET(seqp, NULL);
00891 COMPQUIET(flags, 0);
00892 __db_err(dbp->dbenv,
00893 "library build did not include support for sequences");
00894 return (DB_OPNOTSUP);
00895 }
00896 #endif