Set_bt_compare

Hi all,
I want to use a custom sort of secondary duplicates. But I see the FAQ:
[custom sort of secondary duplicates|http://www.oracle.com/technology/products/berkeley-db/faq/db_faq.html#22]
It is not support.
I use the option #1 instead. It work correctly. (I use Btee Access, and set_bt_compare). But there is another problem: Can I use two bt_compare methods for the secondary db? I should support five compostior method !
I use the compare method by numeric the first, but now I want to change it to name. I close the db, and reload it with the new compare method . but it not work.
Should I create five secondary db by five compostior at one time? It waste too much space.
Is there some better options than it?
Thanks,
wendy.

Hello,
Did you set verbose error messages with either:
http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/C/envset_errfile.html
Or if you don't have a database environment handle, with:
http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/C/dbset_errfile.html
The messaging from either of these calls should provide more information on what the problem is.
Thanks,
Sandra

Similar Messages

  • DB_THREAD and set_bt_compare

    Hi, All
    I set flags DB_THREAD to database before open, and I also use customized compare function. In such situation, should I set DB_DBT_MALLOC both for key and data?
    I come cross error "DB_THREAD mandates memory allocation flag on..." but everything is ok is I don't use set_bt_compare before open it.
    I can't find clear description in document, so need your clarification, thanks.

    Hi,
    You do need to specify an explicit memory allocation function on DBTs when using the DB_THREAD flag. You can use any one of the DB_DBT_MALLOC, DB_DBT_USERMEM or DB_DBT_APPMALLOC flags.
    If you don't it is possible that the buffer used by Berkeley DB to return results will be overwritten by an operation carried out by another thread, causing unexpected results to be seen by the application.
    Regards,
    Alex Gorrod
    Oracle Berkeley DB

  • Determining DB type prior to open for DB- set_bt_compare()

    Presently, I am building an application that opens a table (BDB database)
    that might be DB_BTREE or DB_HASH (depending on how the original user created it).
    The problem is that I do not know in advance of the DB->open() call which it will be. If I call DB->set_bt_compare() prior to opening the "BDB database" (which is the order it must be done), even when the open type is DB_UNKNOWN, it errors if it turns out to be a type DB_HASH due to the BTREE comparison routine.
    Is there a less expensive way to determine DB_BTREE/DB_HASH without doing an open first and hoping for the normal case, and retrying if it errors?
    Thanks, Warren.

    No, that will not help.
    The problem is that I have an UN-opened DB that I have to use for establishing
    the set_bt_compare() routine on. Your documentation states that this must
    be done prior to calling DB->open(). But I don't know how the user originally
    created it, so I don't know in advance what its type is.
    So the problem is that I don't know if the "database" is a BTREE type. If it is,
    then DB->open() works marvelously. If it is of DB_HASH type, it fails on me,
    because it doesn't like the bt compare routine I gave it.
    It would appear that my only recourse would be to release that failed DB instance,
    create another, and not set the compare routine on a subsequent DB->open()
    attempt. But opens are rather expensive, and so I don't really want to do it that way.
    If I could set the compare routine after the DB->open(), I could know what type
    the database is first, and then only set the bt compare routine if it applies. The
    documentation says that it will be ignored if you set that after the open.
    In my opinion, it would be better if DB->open() ignored the established bt
    compare routine, if it doesn't apply (especially when DB_UNKNOWN was
    provided as the type).
    Remember that a user is calling my routine to open a BDB "database" that was
    created (in a file) in some prior session. So I am calling db_create(), then
    setting the bt compare, and then calling DB-open(). But I supply a type of
    DB_UNKNOWN in the open() call, cause I don't know yet what it is.
    My only other recourse is to save the type in another table (I have some overhead
    tables ("databases")), but I was hoping for a DB way to do this instead, as that
    would complicate things further.
    I hope that clarifies.
    Thanks, Warren.

  • About set_bt_compare().

    I am using DB_BTREE access method. In my application, every two keys in the database are different, which I double-check in the customized comparison function. However, this assertion fails to my surprises.
    Is this a normal phenomenon? Will BDB compare a key with itself? And why?

    Thanks for your answers. The reason turns out to be quit normal and makes me laugh. The database I use is DB_BTREE with DB_RECNUM flag enabled. Each time I insert a tuple, I get corresponding recno using the same cursor with DB_GET_RECNO flag. The assertion fails when I try to get the recno. I don't know whether BDB compares the same key again since the reference says 'return the record number associated with the cursor' and 'associated with the cursor' means that the cursor is already pointing to the tuple and there should be no need to compare the keys. Anyway, the puzzle gets an answer.

  • Need help: when using c_get on secondary DB

    Dear experts,
    I am using BDB 4.7 on Linux.
    My DB configuration was created as shown below.
    primary : btree with my own key-comparison callback
    secondary btree associated to the primary DB with my own comparison callback.
    Codes caused error looks like as following
    ret = db_create(&primarydb, dbenv, 0)
    primarydb->set_bt_compare(primarydb, primarydb_compare);
    ret = db_create(&secondarydb, dbenv, 0)
    secondarydb->set_bt_compare(secondarydb, secondarydb_compare);
    ret = secondarydb->cursor(secondarydb,NULL, &cursor);
    key.flags = DB_DBT_MALLOC;
    data.flags = DB_DBT_MALLOC;
    while (...) {
    /* sorted scanning with NULL key */
    ret = cursor->c_get(cursor, &key, &data, DB_NEXT);
    My problem is, in some case, when calling "cursor->c_get(...)" ,
    the primary db's compare function was called with NULL key data
    even if I use the cursor on the secondary indices.
    Any hint would be highly appreciated.
    Best regards,
    Tawan Won

    Hi,
    Would you be able to explain exactly what the problem is? Does your application crash, do you have a stack trace? Does the database verify okay?
    Why do you call c_get with a null key?
    Bogdan Coman

  • Need help with sorting records in primary and secondary databases

    Hi,
    I would like to store data into primary and secondary db in different order. For the main primary, I want it to be ordered by login_ts instead of uuid which is the key.
    For the user secondary database, I want it to be ordered by sip_user. For the timestampe secondary db, I want it to be ordered by login_ts.
    This is what I have right now,
    this is for main
    uuid=029ae227-a188-4ba8-aea4-7cbc26783d6 sip_user=200003 login_ts=1264327630 logout_ts=
    uuid=22966f76-8c8a-4ab4-b832-b36e8f8e14d sip_user=200003 login_ts=1264327688 logout_ts=
    uuid=e1846e4a-e1f5-406d-b903-55905a2533a sip_user=200003 login_ts=1264327618 logout_ts=
    uuid=e2f9a3cb-02d1-47ff-8af8-a3a371e20b5 sip_user=200003 login_ts=1264327613 logout_ts=
    this is for user search
    uuid=029ae227-a188-4ba8-aea4-7cbc26783d6 sip_user=200003 login_ts=1264327630 logout_ts=
    uuid=22966f76-8c8a-4ab4-b832-b36e8f8e14d sip_user=200003 login_ts=1264327688 logout_ts=
    uuid=e1846e4a-e1f5-406d-b903-55905a2533a sip_user=200003 login_ts=1264327618 logout_ts=
    uuid=e2f9a3cb-02d1-47ff-8af8-a3a371e20b5 sip_user=200003 login_ts=1264327613 logout_ts=
    this is for timestamp
    uuid=029ae227-a188-4ba8-aea4-7cbc26783d6 sip_user=200003 login_ts=1264327630 logout_ts=
    uuid=22966f76-8c8a-4ab4-b832-b36e8f8e14d sip_user=200003 login_ts=1264327688 logout_ts=
    uuid=e1846e4a-e1f5-406d-b903-55905a2533a sip_user=200003 login_ts=1264327618 logout_ts=
    uuid=e2f9a3cb-02d1-47ff-8af8-a3a371e20b5 sip_user=200003 login_ts=1264327613 logout_ts=
    but what I want is :
    this is for main
    uuid=e2f9a3cb-02d1-47ff-8af8-a3a371e20b5 sip_user=200003 login_ts=1264327613 logout_ts=
    uuid=e1846e4a-e1f5-406d-b903-55905a2533a sip_user=200004 login_ts=1264327618 logout_ts=
    uuid=029ae227-a188-4ba8-aea4-7cbc26783d6 sip_user=200003 login_ts=1264327630 logout_ts=
    uuid=22966f76-8c8a-4ab4-b832-b36e8f8e14d sip_user=200005 login_ts=1264327688 logout_ts=
    this is for user search
    uuid=e2f9a3cb-02d1-47ff-8af8-a3a371e20b5 sip_user=200003 login_ts=1264327613 logout_ts=
    uuid=029ae227-a188-4ba8-aea4-7cbc26783d6 sip_user=200003 login_ts=1264327630 logout_ts=
    uuid=e1846e4a-e1f5-406d-b903-55905a2533a sip_user=200004 login_ts=1264327618 logout_ts=
    uuid=22966f76-8c8a-4ab4-b832-b36e8f8e14d sip_user=200004 login_ts=1264327688 logout_ts=
    this is for timestamp
    uuid=e2f9a3cb-02d1-47ff-8af8-a3a371e20b5 sip_user=200003 login_ts=1264327613 logout_ts=
    uuid=e1846e4a-e1f5-406d-b903-55905a2533a sip_user=200003 login_ts=1264327618 logout_ts=
    uuid=029ae227-a188-4ba8-aea4-7cbc26783d6 sip_user=200004 login_ts=1264327630 logout_ts=
    uuid=22966f76-8c8a-4ab4-b832-b36e8f8e14d sip_user=200004 login_ts=1264327688 logout_ts=
    Right now, I have:
    int compare_login_ts(dbp, a, b)
         DB *dbp;
         const DBT a, b;
         int time_a = 0;
         int time_b = 0;
         time_a = atoi ( (char *)a->data);
         time_b = atoi ( (char *)b->data);
         return time_a - time_b ;
    for the timestamp secondary, I set that compare function:
              if ((ret = (*sdb)->set_bt_compare(*sdb , compare_login_ts )) != 0){
    Does anyone know how can I make it sorted according?

    Hi,
    The DB->set_bt_compare() is used to compare keys in Btree database. In the callback function, both the DBTs are key, but not data. Please refer to http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/C/dbset_bt_compare.html.
    If you want any field in the data to be sorted, you might create a secondary index on it and define the compare function as you wish.
    Regards,
    Emily Fu, Oracle Berkeley DB

  • DB- get() behavior change as of 4.5.20

    I wanted to post information we have recently learned about new behavior in DB->get(), which is undocumented from what I can tell. This change caused a threading bug in our code when we upgraded from 4.2.52. It also affects DBCursor->get(DB_SET) to a lesser extent.
    Traditionally, DB->get() on a btree produces data, but does not produce a key, since the key passed in is used for exact match. A change was made in 4.5.20 which causes DB->get() to produce a key if a custom comparator function has been specified (set_bt_compare). The comments in the code (in the cursor get function, __db_c_get) indicate this change was made under the assumption that the compare function may be "magic" and the key passed in may not be the same as the key in the database (except in the eyes of the compare function), so the actual database key is now returned.
    Unfortunately, under the assumption that DB->get() treats the key as read-only, we were using a key DBT whose "flags" were zero. The BDB code tries hard to ensure that when a DB is threaded (opened with DB_THREAD) all DBTs which will be written (key or data) have some memory management flag set (DB_DBT_USERMEM, DB_DBT_REALLOC, etc.). Otherwise, BDB will use an internal buffer associated with the (shared) DB handle, causing threading problems. However, in the case of this new behavior, the flag checking was not augmented to account for this case. Instead, the flag checking code still believes a key will only be written if the get() is called with DB_SET_RECNO, DB_CONSUME or DB_CONSUME_WAIT, which are the only cases documented to modify the key DBT.
    To summarize, we have an undocumented change in behavior, combined with a lack of correspondingly expanded flag safety checks, setting up for threading problems of various sorts.
    The simple workaround is to always set the DBT up as DB_DBT_USERMEM, though in this case the key DBT will still be written, perhaps unexpectedly. If the key's buffer was in read-only memory, this would cause an access violation instead of a threading problem.
    Though this change was obviously intentional, I have some trouble understanding how one gets a key into BDB which is different than the key what will be used for retrieval (the use case this change seems to be addressing). But I imagine there was a specific instance of such a situation from some user. Perhaps an additional flag or setting on the DB to control this behavior, letting the user pro-actively indicate the found key should be returned, would reduce unnecessary key copying, as well as avoiding potential bugs. I have to imagine most custom compare functions are for custom sort order, not for performing a magic transformation between the key in the search and the key in the database, and the key used in get is actually identical to the key found in the database.

    Bumping this. Perhaps I wasn't clear. The documentation cited by Sandra does explain that sometimes people use comparison functions that will match on a partial key. But it also specifically says:
    "When partial keys are specified to Berkeley DB, interfaces which retrieve data items based on a user-specified key (for example, DB->get and DBcursor->get with the DB_SET flag), will not modify the user-specified key by returning the actual key stored in the database."
    The part about "will not modify the user-specified key" is the issue. As of 4.5.20, BDB will modify the user-specified key, even if the user-specified key is identical to the stored key. Since it is actually counter to the cited documentation, you can understand that it would be unexpected. The side-effects and results are described in my original posting.
    Since Sandra has found documentation that contradicts the current behavior, I would now consider this new behavior a bug. Such a change really needs to be introduced in a backward compatible way, such as through the use of new flags on the DB handle.

  • How to delete the fist 10 recods from a table ? The problem is real.

    Hi,
    the code below shows that deleting a records using a cursor works well, if your table is out of a environment, but if you are using a environment the things goes different. Please help me, what i am doing wrong ?
    This code is the most clean code i now to do.
    // THE CODE (BEGIN).
    // BDBTEST.cpp : Clean code.
    #include "X:\include\berkeleydb\db_cxx.h"
    #define DWORD               unsigned long int
    #define UINT               unsigned int
    #define DB_ENV_PATH          "Z:\\Test"
    #define DB_FULL_NAME     "Z:\\Test\\Test.db"
    typedef     struct STRTEST
         DWORD     dwID;
         char     caTxt[64];
    } strTest;
    //     Functions.
    int          compare_int     (     Db               *dbp,
                                  const Dbt     *a,
                                  const Dbt     *b);
    void     Save();
    void     Load();
    void     DeleteAll();
    //     Global variables.
    DbEnv     *g_penvDbEnv;
    Db          *g_pdbTest;
    Dbc          *g_pdbcCursor;
    Dbt          g_dbtTestKey;
    Dbt          g_dbtTestData;
    UINT     g_ui32ENVOpenFlags;
    char     g_caError[256];
    int          g_iResult;
    //     Main function.
    int main(int argc, char* argv[])
         g_penvDbEnv     =     NULL;
         g_pdbTest     =     NULL;
         //     First we run without environment (NO ERROR USING g_pdbcCursor->Del(0)).
         remove(DB_FULL_NAME);
         Save();
         Load();
         DeleteAll();
         Load();
         //     Now we run with environment ("Dbc::del: Invalid argument" (err_ = 22) - ERROR USING g_pdbcCursor->Del(0)).
         try
              g_penvDbEnv     =     new     DbEnv(0);
              if(g_penvDbEnv == NULL)
                   return 0;
         catch(DbException &e)
              sprintf(g_caError, "ERRO -> DSDBBD: %s\n", e.what());
              return 0;
         // Set the normal flags for a transactional subsystem. Note that
         // we DO NOT specify DB_RECOVER.
         g_ui32ENVOpenFlags     =     DB_CREATE          |     // If the environment does not exist, create it.
                                       DB_INIT_LOCK     |     // Initialize locking.
                                       DB_INIT_LOG          |     // Initialize logging.
                                       DB_INIT_MPOOL     |     // Initialize the cache.
                                       DB_THREAD          |     // Free-thread the env handle.
                                       DB_INIT_TXN;          // Initialize transactions.
         //     Open/Create environment.
         try
              //     Environment settings.
              g_iResult     =     g_penvDbEnv->set_encrypt("1234", DB_ENCRYPT_AES);
              g_iResult     =     g_penvDbEnv->set_lg_bsize     (1024 * 256);                    //     LOG MEMORY FILE MAX SIZE.
              g_iResult     =     g_penvDbEnv->set_cachesize(0, 1024 * 512, 0);
              g_iResult     =     g_penvDbEnv->set_flags     (DB_AUTO_COMMIT,     1);
              g_iResult     =     g_penvDbEnv->set_flags     (DB_LOG_AUTOREMOVE,     1);
              g_iResult     =     g_penvDbEnv->set_lg_max     (1025 * 1024);                    //     LOG FILE MAX SIZE.
              // Open the environment with full transactional support.
              g_iResult     =     g_penvDbEnv->open(DB_ENV_PATH, g_ui32ENVOpenFlags, 0);
         catch(DbException &e)
              sprintf(g_caError, "ERRO -> DSDBBD: %s\n", e.what());
              return 0;
         remove(DB_FULL_NAME);
         Save();
         Load();
         DeleteAll();     //     Error goes here.
         Load();
         g_penvDbEnv->close(0);
         delete     g_penvDbEnv;
         g_penvDbEnv     =     NULL;
         return 0;
    void     Save()
         int          i;
         int          iResult;
         DWORD     dwID;
         strTest     sttTest;
         if(g_penvDbEnv == NULL)
              g_pdbTest     =     new     Db(NULL, 0);
         else
              g_pdbTest     =     new     Db(g_penvDbEnv, 0);
              //     Setting databases flags     (Just use with environment).
              g_pdbTest     ->set_flags(DB_CHKSUM | DB_ENCRYPT);
         if(g_penvDbEnv == NULL)
              g_pdbTest     ->set_encrypt("1234", DB_ENCRYPT_AES);
         g_pdbTest->set_bt_compare(compare_int);
         g_iResult     =     g_pdbTest->open(NULL, DB_FULL_NAME, NULL, DB_BTREE, DB_CREATE | DB_THREAD, 0);
         dwID     =     1;
         for(i=0;i<100;i++)
              sttTest.dwID     =     dwID;
              sprintf(sttTest.caTxt, "ID = %04u", sttTest.dwID);
              g_dbtTestKey     .set_data((void*) &sttTest.dwID);
              g_dbtTestKey     .set_size(sizeof(DWORD));
              g_dbtTestData     .set_data((void*) &sttTest);
              g_dbtTestData     .set_size(sizeof(sttTest));
              iResult = g_pdbTest->put(0, &g_dbtTestKey, &g_dbtTestData, DB_NOOVERWRITE);
              dwID++;
         g_pdbTest->sync(0);
         g_pdbTest->close(0);
         delete     g_pdbTest;
         g_pdbTest     =     NULL;
    void     Load()
         strTest     *psttTest;
         if(g_penvDbEnv == NULL)
              g_pdbTest     =     new     Db(NULL, 0);
         else
              g_pdbTest     =     new     Db(g_penvDbEnv, 0);
              //     Setting databases flags     (Just use with environment).
              g_pdbTest     ->set_flags(DB_CHKSUM | DB_ENCRYPT);
         if(g_penvDbEnv == NULL)
              g_pdbTest     ->set_encrypt("1234", DB_ENCRYPT_AES);
         g_pdbTest->set_bt_compare(compare_int);
         g_iResult     =     g_pdbTest->open(NULL, DB_FULL_NAME, NULL, DB_BTREE, DB_CREATE | DB_THREAD, 0);
         // Get a cursor
         g_pdbTest->cursor(NULL, &g_pdbcCursor, 0);
         // Iterate over the database, retrieving each record in turn.
         while((g_iResult = g_pdbcCursor->get(&g_dbtTestKey, &g_dbtTestData, DB_NEXT)) == 0)
              //     Get temp struct.
              psttTest     =     (strTest*)     g_dbtTestData.get_data();
         g_pdbcCursor->close();
         g_pdbTest->close(0);
         delete     g_pdbTest;
         g_pdbTest     =     NULL;
    void     DeleteAll()
         strTest     *psttTest;
         try
              if(g_penvDbEnv == NULL)
                   g_pdbTest     =     new     Db(NULL, 0);
              else
                   g_pdbTest     =     new     Db(g_penvDbEnv, 0);
                   //     Setting databases flags     (Just use with environment).
                   g_pdbTest     ->set_flags(DB_CHKSUM | DB_ENCRYPT);
              if(g_penvDbEnv == NULL)
                   g_pdbTest     ->set_encrypt("1234", DB_ENCRYPT_AES);
              g_pdbTest->set_bt_compare(compare_int);
              g_iResult     =     g_pdbTest->open(NULL, DB_FULL_NAME, NULL, DB_BTREE, DB_CREATE | DB_THREAD, 0);
              // Get a cursor
              g_pdbTest->cursor(NULL, &g_pdbcCursor, 0);
              // Iterate over the database, retrieving each record in turn.
              while((g_iResult = g_pdbcCursor->get(&g_dbtTestKey, &g_dbtTestData, DB_NEXT)) == 0)
                   //     Get temp struct.
                   psttTest     =     (strTest*)     g_dbtTestData.get_data();
                   g_iResult     =     g_pdbcCursor->del(0);
         catch (DbException &dbe)
              sprintf(g_caError,     
                        "%s",
                        dbe.what());
         g_pdbcCursor->close();
         g_pdbTest->close(0);
         delete     g_pdbTest;
         g_pdbTest     =     NULL;
    int compare_int(Db dbp, const Dbt a, const Dbt *b)
         int          iReturn;
         DWORD     dwKey1;
         DWORD     dwKey2;
         dwKey1     =     0;
         dwKey2     =     0;
         iReturn     =     0;
         dwKey1     =     *((DWORD*) a->get_data());
         dwKey2     =     *((DWORD*) b->get_data());
         if(dwKey1 > dwKey2)
              iReturn     =     1;
         else
              if(dwKey1 < dwKey2)
                   iReturn     =     -1;
         return     iReturn;
    // THE CODE (END).
    Thanks,
    DelNeto

    Hi all
    I solved it. No documentation about it, but the solution is to use transaction.
    Just use this DeleteAll function that all works fine.
    void     DeleteAll()
         strTest     *psttTest;
         DbTxn     *pTxn;
         try
              pTxn          =     NULL;
              g_pdbTest     =     NULL;
              if(g_penvDbEnv == NULL)
                   g_pdbTest     =     new     Db(NULL, 0);
              else
                   g_pdbTest     =     new     Db(g_penvDbEnv, 0);
                   //     Setting databases flags     (Just use with environment).
                   g_pdbTest     ->set_flags(DB_CHKSUM | DB_ENCRYPT);
              if(g_penvDbEnv == NULL)
                   g_pdbTest     ->set_encrypt("1234", DB_ENCRYPT_AES);
              g_pdbTest->set_bt_compare(compare_int);
              g_iResult     =     g_pdbTest->open(NULL, DB_FULL_NAME, NULL, DB_BTREE, DB_CREATE | DB_THREAD, 0);
              if(g_penvDbEnv == NULL)
                   g_pdbTest->cursor(NULL, &g_pdbcCursor, 0);
              else
                   // Get a cursor.
                   g_penvDbEnv->txn_begin(NULL, &pTxn, 0);
                   g_pdbTest->cursor(pTxn, &g_pdbcCursor, 0);
              // Iterate over the database, retrieving each record in turn.
              while((g_iResult = g_pdbcCursor->get(&g_dbtTestKey, &g_dbtTestData, DB_NEXT)) == 0)
                   //     Get temp struct.
                   psttTest     =     (strTest*)     g_dbtTestData.get_data();
                   g_iResult     =     g_pdbcCursor->del(0);
              g_pdbcCursor->close();
              if(g_penvDbEnv != NULL)
                   pTxn->commit(0);
         catch (DbException &dbe)
              sprintf(g_caError,     
                        "%s",
                        dbe.what());
              g_pdbcCursor->close();
              if(g_penvDbEnv != NULL)
                   pTxn->abort();
         g_pdbTest->close(0);
         delete     g_pdbTest;
         g_pdbTest     =     NULL;
    Thanks to all readers,
    DelNeto

  • Database hangs after retrieving some records....

    hi,
    I create a two level B+-tree index, for the first level i'm using key as logical database name, for the second level B+-tree i'm using some other field in my data. I am retrieving the records based on logical database name. I am using C++ to implement my index.
    In the following code i'm retrieving records from database. Program is behaving differently for different logical database names. For example in my database i have around 4 lakhs records with logical database name 'A' and around 1 lakh of records with logical database name 'B'. The following code displays all B records but programs hangs after retrieving some A records.
    I'm using PAGE_SIZE=8192, numBuffers=2048, and runnig in Fedora Core3.
    DbEnv myEnv(0);
         myEnv.set_cachesize(0, PAGE_SIZE * numBuffers, 0);
         myEnv.set_data_dir("/home/raviov/new/database");
              try {
                   myEnv.open("./", DB_CREATE | DB_INIT_MPOOL, 0);
              catch (DbException &e) {
                   cerr << "Exception occurred: " << e.what() << endl;
                   exit(1);
              db=new Db(&myEnv,0);
              db->set_pagesize(PAGE_SIZE);     
              db->set_bt_compare(compare_int);
         dbname=itoa(p);
         try
         db->open(NULL,
                   "treedb.db",
                   dbname,
                   DB_BTREE,
                   0,
                   0);
         catch(DbException &e)
              cerr << "Failed to open DB object" << endl;
              exit(1);
         db->cursor(NULL,&cursorp,0);
         key=new Dbt();
         data=new Dbt();
         while(ret=(cursorp->get(key,data,DB_NEXT))==0)
              j=*((int*)key->get_data());
              q=(*((struct tuple*)data->get_data())).startPos;
              r=(*((struct tuple*)data->get_data())).endPos;
              s=(*((struct tuple*)data->get_data())).level;
              cout<<"position : "<<j<<"\t";
              cout<<"start : "<<q<<"\t";
              cout<<"end : "<<r<<"\t";
              cout<<"level : "<<s<<"\n";
         if(ret==DB_NOTFOUND)
              cout<<"no records";
              exit(1);
         if(cursorp!=NULL)
              cursorp->close();
         try
              db->close(0);
         catch(DbException &e)
              cerr << "Failed to close DB object" << endl;
              exit(1);
         myEnv.close(0);

    HI Andrei,
    thank you for giving reply, I'm not using any secondary indecies, subdatabases and not using any threads.
    the following code displays index...
    #include <stdio.h>
    #include <db_cxx.h>
    #include <iostream.h>
    #include <db.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    int PAGE_SIZE=8192;
    int numBuffers=2048;
    char *itoa(const int x)
          char buf[100];
          snprintf(buf, sizeof(buf), "%d", x);
           return strdup(buf);
    int compare_int(Db dbp, const Dbt a, const Dbt *b)
      int ai;
      int bi;
      memcpy(&ai,a->get_data(),sizeof(int));
      memcpy(&bi,b->get_data(),sizeof(int));
      return(ai-bi);
    struct tuple
           int startPos;
           int endPos;
           int level;
    main()
         FILE *fp;
         int i,j,k,l,m,n,total=0;
         char dbname[500],filename[500],str [500];
         tuple t;
         Db *db;
         Dbt key,data;
         DbEnv myEnv(0);
         myEnv.set_cachesize(0, PAGE_SIZE * numBuffers, 0);
         try {
                myEnv.open("/home/raviov/Desktop/example", DB_CREATE | DB_INIT_MPOOL, 0);
           catch (DbException &e) {
                  cerr << "Exception occurred: " << e.what() << endl;
                  exit(1);
         for(n=0;n<=84;n++)
              db = new Db(&myEnv, 0);     // Instantiate the Db object
                    db->set_bt_compare(compare_int);
               db->set_pagesize(PAGE_SIZE);
              strcpy(filename,"/home/raviov/Desktop/GTCReport/code/sequence/splitter/tree/");
              strcat(filename,itoa(n));
              fp=fopen(filename,"r");
              if(fp==NULL)
                   cout<<"error in opening the file";
                   exit(0);
              while(fgets (str , 500 , fp)!=NULL)
                   sscanf(str,"%d(%d,%d,%d,%d)",&i,&j,&k,&l,&m);
                   key=new Dbt(&i,sizeof(int));
                   if(total==0)
                        strcpy(dbname,itoa(j));
                   t.startPos=k;
                   t.endPos=l;
                   t.level=m;
                   data=new Dbt(&t,sizeof(t));     
                   if(total==0)
                        try
                             db->open(NULL,
                             "tree.db",
                                       dbname,
                              DB_BTREE,
                                DB_CREATE,
                                0);
                        catch(DbException &e)
                               cerr << "Failed to create DB object" << endl;
                             exit(1);
                        total=99;
                   int ret=db->put(NULL,key,data,DB_NOOVERWRITE);
                   if(ret==DB_KEYEXIST)
                        cout<<"key already exist\n";
                        exit(1);
                   delete key;
                   delete data;
              total=0;
              fclose(fp);
              try
                   db->close(0);
              catch(DbException &e)
                     cerr << "Failed to close DB object" << endl;
                   exit(1);
         myEnv.close(0);
    }The following code retrieves the records from database that we had built above...
    #include <stdio.h>
    #include <db_cxx.h>
    #include <iostream.h>
    #include <db.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    int PAGE_SIZE=8192;
    int numBuffers=2048;
    char *itoa(const int x)
          char buf[100];
          snprintf(buf, sizeof(buf), "%d", x);
           return strdup(buf);
    int compare_int(Db dbp, const Dbt a, const Dbt *b)
      int ai;
      int bi;
      memcpy(&ai,a->get_data(),sizeof(int));
      memcpy(&bi,b->get_data(),sizeof(int));
      return(ai-bi);
    struct tuple
           int startPos;
           int endPos;
           int level;
    main()
         FILE *fp;
         int i,j,k,l,m,n,total=0;
         char *dbname;
         char filename[200],str [100];
         tuple t;
         Db *db;
         Dbt key,data;
         Dbc *cursorp=NULL;
         int ret,x=4;
         char *ravi;
         int p=84763;
         int y=2134872;
         int r,s,q,count=0;
         DbEnv myEnv(0);
         myEnv.set_cachesize(0, PAGE_SIZE * numBuffers, 0);
         myEnv.set_data_dir("/home/raviov/new/database");
              try {
                      myEnv.open("./", DB_CREATE | DB_INIT_MPOOL, 0);
               catch (DbException &e) {
                      cerr << "Exception occurred: " << e.what() << endl;
                      exit(1);
              db=new Db(&myEnv,0);
              db->set_pagesize(PAGE_SIZE);     
              db->set_bt_compare(compare_int);
         dbname=itoa(p);
         try
              db->open(NULL,
                    "tree.db",
                     dbname,
                     DB_BTREE,
                     0,
                     0);
         catch(DbException &e)
                cerr << "Failed to open DB object" << endl;
              exit(1);
         db->cursor(NULL,&cursorp,0);
         key=new Dbt();
         data=new Dbt();
         while(ret=(cursorp->get(key,data,DB_NEXT))==0)
              j=*((int*)key->get_data());
              q=(*((struct tuple*)data->get_data())).startPos;
              r=(*((struct tuple*)data->get_data())).endPos;
              s=(*((struct tuple*)data->get_data())).level;
              cout<<"position   : "<<j<<"\t";
              cout<<"start : "<<q<<"\t";
              cout<<"end   : "<<r<<"\t";
              cout<<"level   : "<<s<<"\n";
              delete key;
              delete data;
         if(ret==DB_NOTFOUND)
              cout<<"no records";
              exit(1);
         if(cursorp!=NULL)
              cursorp->close();
         try
              db->close(0);
         catch(DbException &e)
                cerr << "Failed to close DB object" << endl;
              exit(1);
         myEnv.close(0);     
    }

  • DB_DBT_MALLOC was set when secondary db's callback function was called!

    I have a secondary db associated with a primary db,when i insert some test records into primary db
    ,i saw my sdb_callback was called twice!the first call with the correct data,but the seocond call
    was with wrong data,data.size was wrong ,with a big value and flags was set to DB_DBT_MALLOC ,
    what should i do when the callback was called twice?just return DB_DONOTINDEX?
    i modified the example code from source code/example_c/bench_001.c,make the bulk_fill the DB to
    have a secondary as following
    int sdb_callback(DB sdbp,          / secondary db handle */
                                  const DBT pkey,   / primary db record's key */
                                  const DBT pdata,  / primary db record's data */
                                  DBT skey)         / secondary db record's key */
         if(pdata->flags & DB_DBT_MALLOC)
              fprintf(stderr,"DB_DBT_MALLOC fired size:%d ksize:%d \r\n",pdata->size,pkey->size);
              return DB_DONOTINDEX;
         }else
              return DB_DONOTINDEX;
    FOR work WITH secondary db,i comment following out
         //if ((ret = dbp->set_flags(dbp, DB_DUP)) != 0) {
         //     dbp->err(dbp, ret, "set_flags");
         //     goto err;
         char sdb_filename[256];
         sprintf(sdb_filename, "s_%s",DATABASE );
         if ((ret = db_create(&sdbp, dbenv, 0)) != 0) {
              dbp->err(dbp, ret, "crate");
              exit(EXIT_FAILURE);
         /* set page size */
         if((ret = sdbp->set_pagesize(sdbp, pagesize)) != 0){
              dbp->err(dbp, ret, "crate");
              exit(EXIT_FAILURE);
         /* allow sorted duplicates. */
         /* try to open db*/
         ret = sdbp->open(sdbp, NULL, sdb_filename, NULL, DB_BTREE, DB_CREATE, 0664);
         if(ret != 0)
              dbp->err(dbp, ret, "%s: sdb open", DATABASE);
         dbp->associate(dbp, NULL, sdbp, sdb_callback, 0);
    then i run bulk_fill test,DB_DBT_MALLOC was OFTEN fired,but not every put!
    Edited by: feiman on May 23, 2010 4:35 AM

    following are codes from example_c bench_001.c
    i run ./a.out -B
    then it appears that when one record input to main db,secondary db's callback was called twice,except the FIRST record!!!
    #include <sys/types.h>
    #include <sys/time.h>
    #include <assert.h>
    #include <stdlib.h>
    #include <string.h>
    #ifdef _WIN32
    extern int getopt(int, char * const *, const char *);
    #else
    #include <unistd.h>
    #endif
    #include <db.h>
    #define     DATABASE     "bench_001.db"
    int     bulk_fill(DB_ENV *, DB *, int, u_int, int, int, int *, int *);
    int     compare_int(DB *, const DBT *, const DBT *);
    DB_ENV db_init(char , char *, u_int, int);
    int     main(int, char *[]);
    void     usage(void);
    const char
         progname = "bench_001";          / Program name. */
    int
    sdb_callback(DB sdbp,          / secondary db handle */
                                  const DBT pkey,   / primary db record's key */
                                  const DBT pdata,  / primary db record's data */
                                  DBT skey)         / secondary db record's key */
         skey->data = pkey->data;
         skey->size = pkey->size;
    fprintf(stderr,"callback called size:%d ksize:%d \r\n",pdata->size,pkey->size);
         return 0;
    * db_init --
    *     Initialize the environment.
    DB_ENV *
         db_init(home, prefix, cachesize, txn)
         char home, prefix;
    u_int cachesize;
    int txn;
         DB_ENV *dbenv;
         u_int32_t flags;
         int ret;
         if ((ret = db_env_create(&dbenv, 0)) != 0) {
              dbenv->err(dbenv, ret, "db_env_create");
              return (NULL);
         dbenv->set_errfile(dbenv, stderr);
         dbenv->set_errpfx(dbenv, prefix);
         (void)dbenv->set_cachesize(dbenv, 0,
              cachesize == 0 ? 50 * 1024 * 1024 : (u_int32_t)cachesize, 0);
         flags = DB_CREATE | DB_INIT_MPOOL;
         if (txn)
              flags |= DB_INIT_TXN | DB_INIT_LOCK;
         if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0) {
              dbenv->err(dbenv, ret, "DB_ENV->open: %s", home);
              (void)dbenv->close(dbenv, 0);
              return (NULL);
         return (dbenv);
    * bulk_fill - bulk_fill a db
    *     Since we open/created the db with transactions (potentially),
    * we need to populate it with transactions. We'll bundle the puts
    * UPDATES_PER_BULK_PUT to a transaction.
    #define     UPDATES_PER_BULK_PUT     3
    int
         bulk_fill(dbenv, dbp, txn, datalen, num, dups, countp, iterp)
         DB_ENV *dbenv;
    DB *dbp;
    u_int datalen;
    int txn, num, dups;
    int countp, iterp;
         DBT key, data;
         u_int32_t flag = 0;
         DB_TXN *txnp;
         struct data {
              int id;
              char str[1];
         } *data_val;
         int count, i, iter, ret;
         void ptrk, ptrd;
         int iCnt = 0;
         time_t now,then;
         time(&now);
         time(&then);
         * Insert records into the database, where the key is the user
         * input and the data is the user input in reverse order.
         txnp = NULL;
         ret = 0;
         count = 0;
         iter = 0;
         ptrk = ptrd = NULL;
         data_val = malloc(datalen);
         memcpy(data_val->str, "0123456789012345678901234567890123456789",
              datalen - sizeof(data_val->id));
         memset(&key, 0, sizeof(DBT));
         memset(&data, 0, sizeof(DBT));
         * Need to account for proper buffer size,
         * The buffer must be at least as large as the page size of
         * the underlying database, aligned for unsigned integer
         * access, and be a multiple of 1024 bytes in size.
         key.ulen = (u_int32_t)UPDATES_PER_BULK_PUT *
              sizeof(u_int32_t) * datalen * 1024;
         key.flags = DB_DBT_USERMEM | DB_DBT_BULK;
         key.data = malloc(key.ulen);
         data.ulen = (u_int32_t)UPDATES_PER_BULK_PUT *
              (u_int32_t)datalen * 1024;
         data.flags = DB_DBT_USERMEM | DB_DBT_BULK;
         data.data = malloc(data.ulen);
         if (dups)
              flag |= DB_MULTIPLE;
         else
              flag |= DB_MULTIPLE_KEY;
         DB_MULTIPLE_WRITE_INIT(ptrk, &key);
         if (dups)
              DB_MULTIPLE_WRITE_INIT(ptrd, &data);
         for (i = 0; i < num; i++) {
              if (txn != 0 && (i+1) % UPDATES_PER_BULK_PUT == 0) {
                   if (txnp != NULL) {
                        ret = txnp->commit(txnp, 0);
                        txnp = NULL;
                        if (ret != 0)
                             goto err;
                   if ((ret =
                        dbenv->txn_begin(dbenv, NULL, &txnp, 0)) != 0)
                        goto err;
              data_val->id = 0;
              do {
                   if (dups) {
                        DB_MULTIPLE_WRITE_NEXT(ptrk, &key,
                             &i, sizeof(i));
                        assert(ptrk != NULL);
                        DB_MULTIPLE_WRITE_NEXT(ptrd, &data,
                             data_val, datalen);
                        assert(ptrd != NULL);
                   else {
                        DB_MULTIPLE_KEY_WRITE_NEXT(ptrk,
                             &key, &i, sizeof(i), data_val, datalen);
                        assert(ptrk != NULL);
                   if ((i+1) % UPDATES_PER_BULK_PUT == 0) {
                        switch (ret = dbp->put(dbp, txnp, &key, &data, flag)) {
                        case 0:
                             iter++;
                             free (key.data);
                             free (data.data);
                             memset(&key, 0, sizeof(DBT));
                             memset(&data, 0, sizeof(DBT));
                             key.ulen =
                                  (u_int32_t)UPDATES_PER_BULK_PUT *
                                  sizeof(u_int32_t) * datalen * 1024;
                             key.flags = DB_DBT_USERMEM|DB_DBT_BULK;
                             key.data = malloc(key.ulen);
                             data.ulen =
                                  (u_int32_t)UPDATES_PER_BULK_PUT *
                                  (u_int32_t)datalen * 1024;
                             data.flags =
                                  DB_DBT_USERMEM|DB_DBT_BULK;
                             data.data = malloc(data.ulen);
                             DB_MULTIPLE_WRITE_INIT(ptrk, &key);
                             if (dups)
                                  DB_MULTIPLE_WRITE_INIT(ptrd, &data);
                             break;
                        default:
                             dbp->err(dbp, ret, "Bulk DB->put");
                             free (key.data);
                             free (data.data);
                             goto err;
                   count++;
              } while (++data_val->id < dups);
         if ((num % UPDATES_PER_BULK_PUT) != 0) {
              switch (ret = dbp->put(dbp, txnp, &key, &data, flag)) {
              case 0:
                   iter++;
                   free (key.data);
                   free (data.data);
                   break;
              default:
                   free (key.data);
                   free (data.data);
                   dbp->err(dbp, ret, "Bulk DB->put");
                   goto err;
         if (txnp != NULL)
              ret = txnp->commit(txnp, 0);
         printf("%d\n", count);
         *countp = count;
         *iterp = iter;
         return (ret);
    err:     if (txnp != NULL)
                   (void)txnp->abort(txnp);
              return (ret);
    int
         main(argc, argv)
         int argc;
    char *argv[];
         extern char *optarg;
         extern int optind;
         DB dbp,sdbp;
         DB_ENV *dbenv;
         DB_TXN *txnp;
         struct timeval start_time, end_time;
         double secs;
         u_int cache, datalen, pagesize;
         int biter, ch, count, dups, env, init, iter, num;
         int ret, rflag, txn, bulk, delete;
         txnp = NULL;
         datalen = 20;
         iter = num = 100;
         env = 1;
         dups = init = rflag = txn = bulk = delete = 0;
         pagesize = 65536;
         cache = 1000 * pagesize;
         while ((ch = getopt(argc, argv, "c:d:EIi:l:n:p:RTBD")) != EOF)
              switch (ch) {
              case 'c':
                   cache = (u_int)atoi(optarg);
                   break;
              case 'd':
                   dups = atoi(optarg);
                   break;
              case 'E':
                   env = 0;
                   break;
              case 'I':
                   init = 1;
                   break;
              case 'i':
                   iter = atoi(optarg);
                   break;
              case 'l':
                   datalen = (u_int)atoi(optarg);
                   break;
              case 'n':
                   num = atoi(optarg);
                   break;
              case 'p':
                   pagesize = (u_int)atoi(optarg);
                   break;
              case 'R':
                   rflag = 1;
                   break;
              case 'T':
                   txn = 1;
                   break;
              case 'B':
                   bulk = 1;
                   break;
              case 'D':
                   delete = 1;
                   break;
              case '?':
              default:
                   usage();
         argc -= optind;
         argv += optind;
         /* Remove the previous database. */
         if (!rflag) {
              if (env)
                   (void)system("rm -rf BENCH_001; mkdir BENCH_001");
              else
                   (void)unlink(DATABASE);
         dbenv = NULL;
         if (env == 1 &&
              (dbenv = db_init("BENCH_001", "bench_001", cache, txn)) == NULL)
              return (-1);
         if (init)
              exit(0);
         /* Create and initialize database object, open the database. */
         if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
              fprintf(stderr,
                   "%s: db_create: %s\n", progname, db_strerror(ret));
              exit(EXIT_FAILURE);
         dbp->set_errfile(dbp, stderr);
         dbp->set_errpfx(dbp, progname);
         if ((ret = dbp->set_bt_compare(dbp, compare_int)) != 0) {
              dbp->err(dbp, ret, "set_bt_compare");
              goto err;
         if ((ret = dbp->set_pagesize(dbp, pagesize)) != 0) {
              dbp->err(dbp, ret, "set_pagesize");
              goto err;
         if (dups && (ret = dbp->set_flags(dbp, DB_DUP)) != 0) {
              dbp->err(dbp, ret, "set_flags");
         goto err;
         if (env == 0 && (ret = dbp->set_cachesize(dbp, 0, cache, 0)) != 0) {
              dbp->err(dbp, ret, "set_cachesize");
              goto err;
         //if ((ret = dbp->set_flags(dbp, DB_DUP)) != 0) {
         //     dbp->err(dbp, ret, "set_flags");
         //     goto err;
         if (txn != 0)
              if ((ret = dbenv->txn_begin(dbenv, NULL, &txnp, 0)) != 0)
                   goto err;
         if ((ret = dbp->open(
              dbp, txnp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
                   dbp->err(dbp, ret, "%s: open", DATABASE);
                   if (txnp != NULL)
                        (void)txnp->abort(txnp);
                   goto err;
         char sdb_filename[256];
         sprintf(sdb_filename, "s_%s",DATABASE );
         if ((ret = db_create(&sdbp, dbenv, 0)) != 0) {
              dbp->err(dbp, ret, "crate");
              exit(EXIT_FAILURE);
         /* set page size */
         if((ret = sdbp->set_pagesize(sdbp, pagesize)) != 0){
              dbp->err(dbp, ret, "crate");
              exit(EXIT_FAILURE);
         /* allow sorted duplicates. */
         /* try to open db*/
         ret = sdbp->open(sdbp, NULL, sdb_filename, NULL, DB_BTREE, DB_CREATE, 0664);
         if(ret != 0)
              dbp->err(dbp, ret, "%s: sdb open", DATABASE);
         dbp->associate(dbp, NULL, sdbp, sdb_callback, 0);
         if (txnp != NULL)
              ret = txnp->commit(txnp, 0);
         txnp = NULL;
         if (ret != 0)
              goto err;
              if (bulk) {
                   /* Time the get loop. */
                   (void)gettimeofday(&start_time, NULL);
                   if ((ret = bulk_fill(dbenv, dbp, txn, datalen,
                        num, dups, &count, &biter)) != 0)
                        goto err;
                   (void)gettimeofday(&end_time, NULL);
                   secs =
                        (((double)end_time.tv_sec * 1000000 +
                        end_time.tv_usec) -
                        ((double)start_time.tv_sec * 1000000 +
                        start_time.tv_usec))
                        / 1000000;
                   printf("%d records put using %d batches",
                        count, biter);
                   printf(" in %.2f seconds: ", secs);
                   printf("%.0f records/second\n", (double)count / secs);
         /* Close everything down. */
         if ((ret = dbp->close(dbp, rflag ? DB_NOSYNC : 0)) != 0) {
              fprintf(stderr,
                   "%s: DB->close: %s\n", progname, db_strerror(ret));
              return (1);
         return (ret);
    err:     (void)dbp->close(dbp, 0);
         return (1);
    int
         compare_int(dbp, a, b)
         DB *dbp;
    const DBT a, b;
         int ai, bi;
         dbp = dbp;                    /* Lint. */
         * Returns:
         *     < 0 if a < b
         *     = 0 if a = b
         *     > 0 if a > b
         memcpy(&ai, a->data, sizeof(int));
         memcpy(&bi, b->data, sizeof(int));
         return (ai - bi);
    void
         usage()
         (void)fprintf(stderr, "usage: %s %s\n\t%s\n",
              progname, "[-EIRTBE] [-c cachesize] [-d dups]",
              "[-i iterations] [-l datalen] [-n keys] [-p pagesize]");
         exit(EXIT_FAILURE);
    }

  • Strange problem while building a secondary index.

    Hi,
    I have a strange problem in creating a secondary index which is a part of primary data.
    I tested my program and a working sample program
    My data scheme looks like:
       Key = unique string
       Data = structure {
                        time_t timestamp;
        Secondary Key = timestamp in data (NOT unique)
    My BDB environment flags is "DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL | DB_THREAD"
    The primary DB is created as BTREE with a custom key compare function provided by calling DB->set_bt_compare.
    int my_key_compare(DB *db, const DBT *key1, const DBT *key2)
         const char *k1_v = (const char *)key1->data;
         const char *k2_v = (const char *)key2->data;
         return strcmp(k1_v, k2_v);
    The secondary Index DB is created as BTREE while permitting duplication. (DB_DUPSORT)
    It has two custom callback functions; one for data compare, the other for extracting a data from the primary data.
    int my_extract_timestamp(DB *db, const DBT *primary_key, const DBT *primary_data, DBT *secdondary_key)
         secondary_key->data = ( (MY_DATA *)(primary_data->data))->timestamp;
         secondary_key->size = sizeof(time_t);
         return 0;
    int my_secondary_dup_compare(DB *db, const DBT *key1, const DBT *key2)
         time_t      k1_v = *(time_t *)key1->data;
         time_t      k2_v = *(time_t *)key2->data;
         return k1_v - k2_v;
    The function 'my_extract_timestamp' is set by calling DB->associate().
    My problem is 'my_secondary_dup_compare' function called with a strange DBT values.
    I think the values should point to the value provided from my_extract_timestamp(), but they pointed to
    the key which provided when calling DB->put on the primary DB.
    Could somebody help me ?
    Any help highly appreciated.

    Hi,
    In the secondary database, the key is what you extract and the data is the key of the primary database. As your primary key is a unique string, your data in secondary database is also a unique string. The DB->set_dup_compare sets the comparison function for the duplicate data, so you are comparing time stamps on unique strings, not on what you extract.
    As you are comparing the time stamps which are the keys of secondary database, I guess here you want to set the bt_compare function instead of the dup_compare for the secondary database.
    Also, about this sentence:
    secondary_key->data = ( (MY_DATA *)(primary_data->data))->timestamp;
    The DBT.data should be an address, but this is a value here instead of an address.
    Regards,
    Winter, Oracle Berkeley DB

  • Retrieving random key-value pair

    I am storing a large number of items I want to randomly select from. Say for example I want to store a massive list of competition entrants (10-100 million) and I want to keep randomly pulling out winners (and removing them ideally).
    At the moment I'm using a cursor on a DH_HASH database (I have tried a BTREE too) as follows:
    g_db.cursor(NULL, &dbc, 0);
    int res = dbc->get(&key, &data, DB_LAST); // tried DB_FIRST too
    This works somewhat ok, depending how I'm adding entries in the first place. If I add names very randomly it works fine. If, however, I add names perfectly in order (say I'm entering them from a pre-sorted list) I consistently get similar results back, say a lot of entries beginning "John".
    I tried reversing the stored keys, which again helps with randomisation, but then I end up with a lot of senoJ (Jones) entries.
    What I really want is completely randomized retrieval, but google hasn't helped me.
    Any help gratefully received!
    Cheers.
    (Note: my example is purely fictitious!)

    Hello,
    Perhaps making use of the set_h_hash method to set a user-defined hash function documented in the Reference Guide at:
    http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/C/dbset_h_hash.html
    Or setting your own Btree comparison via the set_bt_compare method documented in the Reference Guide at:
    http://www.oracle.com/technology/documentation/berkeley-db/db/programmer_reference/bt_conf.html#am_conf_bt_compare
    would help achieve the desired results.
    Thanks,
    Sandra

  • Open fails when using DB_DIRECT_DB

    Hi,
    I'm trying to use the DB_DIRECT_DB flag to bypass the filesystem cache for some experiments I'm running (to clarify results, not for performance reasons). I'm using BDB 4.5.20 (C++ API) with kernel version 2.6.17-1.2142_FC4smp on Fedora Core 4.
    I initialize a database handle as follows:
        Db* db = new Db(NULL, 0);
        db->set_cachesize(0, 1024*CACHE_SIZE, 1); // in kB
        DbEnv* env = db->get_env();
        env->set_flags(DB_DIRECT_DB, 1);
        env->set_msgfile(stderr);
        env->set_errfile(stderr);
        db->set_bt_compare(compare_int);
        db->open(NULL, file, NULL, DB_BTREE, 0, 0);The file already exists (was created by the same version of Berkeley DB, although without the O_DIRECT flag) and is 37MB on disk. Calling db->open generates this error:
    read: 0x86735f0, 4096: Invalid argument
    terminate called after throwing an instance of 'DbException'
      what():  Db::open: Invalid argumentThat address doesn't seem to be aligned to anything...
    Without DB_DIRECT_DB, everything works. I've google'd around but can't find anything useful--I'd appreciate any suggestions!
    Thanks,
    Daniel

    hello,
    You may find the information in the following post helpful as
    it is on a related issue with read() and DB_DIRECT_DB.
    Bug: Specifying DB_DIRECT_DB crashes BDB 4.4.20
    thanks,
    Sandra

  • Sorting records in Sort and Rank report

    I created a Top 10 report based on the Sort and Rank template. The report behaves well at first, giving me 10 records nicely sorted. However, after having run it a few times with various parameters, the sorting seems to be random.
    The EVENE() in cell I33 refers to the row set in cell F5:
    TopCount(Descendants([ENTITY].[RepEntities], 99, LEAVES),10,([ENTITY].CurrentMember,[TIME].[2009.JAN],[RCFINANCE].[31_RC],[CATEGORY].[ACTUAL],[RPTCURRENCY].[LC],[COUNTERPART].[ALL_Counterpart],[MEASURES].[YTD],[DATASRC].[LegalTotal],[ORGANIZATION].[ALL_Organization],[FLOWDETAIL].[All_F]))
    In cell F6, there is an Order expression:
    Order(Descendants([ENTITY].[RepEntities], 99, LEAVES),([ENTITY].CurrentMember,[TIME].[2009.JAN],[RCFINANCE].[31_RC],[CATEGORY].[ACTUAL],[RPTCURRENCY].[LC],[COUNTERPART].[ALL_Counterpart],[MEASURES].[YTD],[DATASRC].[LegalTotal],[ORGANIZATION].[ALL_Organization],[FLOWDETAIL].[All_F]),BDESC)
    However, there seems to be no reference the this expression in EVENE() or elsewhere, which I guess is why the sorting doesn't work.
    Is anyone familiar with the Sort and Rank template and can tell me where to include this Order expression and the syntax for it? My version is 7.0M.
    Cheers,
    Cecilia

    Hi,
    The DB->set_bt_compare() is used to compare keys in Btree database. In the callback function, both the DBTs are key, but not data. Please refer to http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/C/dbset_bt_compare.html.
    If you want any field in the data to be sorted, you might create a secondary index on it and define the compare function as you wish.
    Regards,
    Emily Fu, Oracle Berkeley DB

  • Bt_compare_fcn_type: Second DBT corrupted?

    Folks-
    I have a BTree db, opened as part of an env:
    cEnvFlags = DB_CREATE|DB_INIT_LOCK|DB_INIT_LOG |DB_INIT_MPOOL|DB_INIT_TXN;
    m_pDbEnv = new DbEnv(0);
    m_pDbEnv->open("Env_Home", cEnvFlags, 0);
    // db
    m_pdb = new Db(m_pDbEnv, 0);
    m_pdbWK->set_bt_compare(bt_compare_fcn_type_wk);
    m_pdbWK->open(NULL, "MY_DB" NULL, DB_BTREE, DB_CREATE|DB_AUTO_COMMIT, 0);
    I insert a new record with the key set to Windows GetTickCount() function (to get a unique number since the start of 'this' session)
    DWORD dw = GetTickCount();
    Dbt key;
    key.set_data(&dw);
    key.set_ulen(sizeof(DWORD));
    Dbt data(pData, dataLen);
    try
    m_pdbWK->put(NULL, &key, &data, 0);
    catch(DbException &e)
    in my compare function I do the following:
    int bt_compare_fcn_type_wk(DB db, const DBT dbt1, const DBT *dbt2)
    DWORD dw1, dw2;
    memcpy(&dw1, dbt1->data, sizeof(DWORD));
    memcpy(&dw2, dbt2->data, sizeof(DWORD));
    if (dw1 == dw2)
    return 0;
    else
    return dw1 > dw2;
    However dbt2 does not appear to point to any valid data. The size and ulen members are always 0 and the *(data) memory location does not have valid data.
    I was expecting dbt2 to be the key from the 'last' insert. What am I doing wrong here?
    I'm using MS VC++ 6.0 on XP Prof.
    Any help is greatly appreciated.

    The dbts passed to your callback are either the one passed in by the application, or a record that is in the database. So I suspect you have somehow inserted an empty key into the database (which Berkeley DB supports without complaining), and you're now seeing that record in the callback when Berkeley DB is finding the correct location for the newly-inserted key.
    Take a look at the data in the database (the easiest way is to run the "db_dump" utility against your database and check for blank lines).
    If you don't see an empty key in the db_dump output, can you please post a stack dump for when the callback hits this?
    Regards,
    Michael Cahill, Oracle.

Maybe you are looking for