title: Berkeley DB: stuck at futex_wait because of previous abnormal quit during c api call
body: <p>I'm programming in C, using berkeley db 4.3 (/usr/lib64/libdb-4.3.so) on RHEL5.6 with kernel 2.6.18-238_xen_AMD64.</p>
  
  <p>In my tests (writing 1,000,000 key/value pairs), if one process quitted abnormally (ctrl + c, kill, or assert fails) while an operation on the db is in process, later operation on that db would be blocked upon opening. Strace shows that the process stuck at a futex(ptr_to_something, FUTEX_WAIT, 2, NULL) call after opening the __db.00x(e.g __db.001, __db.002, __db.003) files.</p>
  
  <p>The only way I know to clear the lock is to remove __db.00x files, and following tests showed that the database is not damaged. It meets my requirement, but I'm just wondering whether there's a better(or more elegant) way to solve this problem. </p>
  
  <p>Here I listed some strace stderr and the code to operate the database which may help.</p>
  
  <p><em>some of the strace stderr</em> </p>
  
  <pre><code>...  
  open("__db.001", O_RDWR)                = 3  
  fcntl(3, F_SETFD, FD_CLOEXEC)           = 0  
  fstat(3, {st_mode=S_IFREG|0640, st_size=24576, ...}) = 0  
  close(3)                                = 0  
  open("__db.001", O_RDWR)                = 3  
  fcntl(3, F_SETFD, FD_CLOEXEC)           = 0  
  mmap(NULL, 24576, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0x2afcc4149000  
  close(3)                                = 0
  futex(0x2afcc4149000, FUTEX_WAIT, 2, NULL **[[stuck here]]**  
  </code></pre>
  
  <p><em>code to operate the database</em></p>
  
  <pre><code>typedef DB* db_handle;
  db_handle bdb_open(const char *filename, u_int32_t cache_size_mb)
  {
      int ret;
      DB_ENV *env;
      db_handle dbp;
      u_int32_t flags = DB_CREATE | DB_THREAD | DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_LOCK ;
      u_int32_t gb = cache_size_mb / 1024, mb = cache_size_mb % 1024;
  
      if (ret = db_env_create(&amp;env, 0)) {
          fprintf(stderr, "db_env_create:%d, %s\n", ret, db_strerror(ret));
          exit(EXIT_FAILURE);
      }
  
      if (ret = env-&gt;set_timeout(env, 3 * 1000000, DB_SET_LOCK_TIMEOUT)) {
          fprintf(stderr, "env-&gt;set_timeout:%d, %s\n", ret, db_strerror(ret));
          exit(EXIT_FAILURE);
      }
  
      if (ret = env-&gt;set_lk_detect(env, DB_LOCK_DEFAULT)) { /* this seems to be of no use in my case */
          fprintf(stderr, "env-&gt;set_lk_detect:%d, %s\n", ret, db_strerror(ret));
          exit(EXIT_FAILURE);
      }
  
      if (ret = env-&gt;set_cachesize(env, gb, mb * 1024 * 1024, 0)) {
          fprintf(stderr, "env-&gt;set_cachesize:%d, %s\n", ret, db_strerror(ret));
          exit(EXIT_FAILURE);
      }
  
      if ((ret = env-&gt;open(env, NULL, flags, 0)) != 0) {
          fprintf(stderr, "db_env_open:%d, %s\n", ret, db_strerror(ret));
          exit(EXIT_FAILURE);
      }
  
      if (ret = db_create(&amp;dbp, env, 0)) {
          fprintf(stderr, "db_create:%d, %s\n", ret, db_strerror(ret));
          exit(EXIT_FAILURE);
      }
  
      if (ret = dbp-&gt;open(dbp, NULL, filename, NULL, DB_BTREE, flags, 0664)) {
          fprintf(stderr, "dbp-&gt;open:%d, %s\n", ret, db_strerror(ret));
          exit(EXIT_FAILURE);
      }
  
      return dbp;
  }
  
  int bdb_put(db_handle db, void* key, u_int32_t keylen, void* val, u_int32_t vallen)
  {
      DBT dkey, dval;
      bzero(&amp;dkey, sizeof(dkey));
      bzero(&amp;dval, sizeof(dval));
      dkey.data = key, dkey.size = keylen;
      dval.data = val, dval.size = vallen;
      return db-&gt;put(db, NULL, &amp;dkey, &amp;dval, 0);
  }
  
  int bdb_get(db_handle db, void* key, const u_int32_t keylen,
                            void* buf, u_int32_t buflen, u_int32_t* nwrite)
  {
      DBT dkey, dval;
      bzero(&amp;dkey, sizeof(dkey));
      bzero(&amp;dval, sizeof(dval));
      dkey.data = key, dkey.size = keylen;
      dval.data = buf, dval.ulen = buflen, dval.flags = DB_DBT_USERMEM;
      int ret = db-&gt;get(db, NULL, &amp;dkey, &amp;dval, 0);
      if (ret == 0 &amp;&amp; nwrite != NULL)
          *nwrite = dval.size;
      return ret;
  }
  </code></pre>