Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

sequence.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2004-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: sequence.c,v 12.28 2005/10/24 19:22:00 bostic Exp $
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  * Sequences must be architecture independent but they are stored as user
00052  * data in databases so the code here must handle the byte ordering.  We
00053  * store them in little-endian byte ordering.  If we are on a big-endian
00054  * machine we swap in and out when we read from the database. seq->seq_rp
00055  * always points to the record in native ordering.
00056  *
00057  * Version 1 always stored things in native format so if we detect this we
00058  * upgrade on the fly and write the record back at open time.
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  * db_sequence_create --
00106  *      DB_SEQUENCE constructor.
00107  *
00108  * EXTERN: int db_sequence_create __P((DB_SEQUENCE **, DB *, u_int32_t));
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         /* Check for invalid function flags. */
00129         switch (flags) {
00130         case 0:
00131                 break;
00132         default:
00133                 return (__db_ferr(dbenv, "db_sequence_create", 0));
00134         }
00135 
00136         /* Allocate the sequence. */
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  * __seq_open --
00164  *      DB_SEQUENCE->open method.
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         /* Check for replication block. */
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                 /* INC is the default. */
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          * The first release was stored in native mode.
00299          * Check the version number before swapping.
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                  * The database may have moved from one type
00326                  * of machine to another, check here.
00327                  * If we moved from little-end to big-end then
00328                  * the swap above will make the version correct.
00329                  * If the move was from big to little
00330                  * then we need to swap to see if this
00331                  * is an old version.
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          * It's an error to specify a cache larger than the range of sequences.
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         /* Release replication block. */
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  * __seq_get_cachesize --
00376  *      Accessor for value passed into DB_SEQUENCE->set_cachesize call.
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  * __seq_set_cachesize --
00392  *      DB_SEQUENCE->set_cachesize.
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          * It's an error to specify a cache larger than the range of sequences.
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  * __seq_get_flags --
00424  *      Accessor for flags passed into DB_SEQUENCE->open call
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  * __seq_set_flags --
00440  *      DB_SEQUENCE->set_flags.
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  * __seq_initial_value --
00473  *      DB_SEQUENCE->initial_value.
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  * __seq_get_range --
00501  *      Accessor for range passed into DB_SEQUENCE->set_range call
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  * __seq_set_range --
00518  *      SEQUENCE->set_range.
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          * Create a local transaction as necessary, check for consistent
00562          * transaction usage, and, if we have no transaction but do have
00563          * locking on, acquire a locker id for the handle lock acquisition.
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         /* Check for consistent transaction usage. */
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          * Check whether this operation will cause the sequence to wrap.
00604          *
00605          * The sequence minimum and maximum values can be INT64_MIN and
00606          * INT64_MAX, so we need to do the test carefully to cope with
00607          * arithmetic overflow.  The first part of the test below checks
00608          * whether we will hit the end of the 64-bit range.  The second part
00609          * checks whether we hit the end of the sequence.
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                         /* Don't wrap just to fill the cache. */
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                 /* See if we are at the end of the 64 bit range. */
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                         /* Don't wrap just to fill the cache. */
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                 /* See if we are at the end of the 64 bit range. */
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         /* Check for replication block. */
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         /* Release replication block. */
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  * __seq_get_db --
00747  *      Accessor for dbp passed into DB_SEQUENCE->open call
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  * __seq_get_key --
00763  *      Accessor for key passed into DB_SEQUENCE->open call
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  * __seq_close --
00781  *      Close a sequence
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  * __seq_remove --
00816  *      Remove a sequence from the database.
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         /* Check for replication block. */
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         /* Release replication block. */
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  * __seq_chk_cachesize --
00859  *      Validate the cache size vs. the range.
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          * It's an error to specify caches larger than the sequence range.
00869          *
00870          * The min and max of the range can be either positive or negative,
00871          * the difference will fit in an unsigned variable of the same type.
00872          * Assume a 2's complement machine, and simply subtract.
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 /* !HAVE_SEQUENCE */
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 /* HAVE_SEQUENCE */

Generated on Sun Dec 25 12:14:49 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2