Пример #1
0
int main(void)
{
  int ret, ret_c;
  u_int32_t db_flags, env_flags;
  DB *dbp;
  DB_ENV *envp;
  DBT key, data;
  DB_TXN *txn;
  const char *db_home_dir = "/tmp/mai-test-good-1/";
  const char *file_name = "mydb.db";
  const char keystr[BUF_SIZE];
  const char datastr[BUF_SIZE];
  int i = 0;

  dbp = NULL;
  envp = NULL;

  /* Open the environment */
  ret = db_env_create(&envp, 0);
  if (ret != 0) {
    fprintf(stderr, "Error creating environment handle: %s\n",
        db_strerror(ret));
    return (EXIT_FAILURE);
  }

  env_flags = DB_CREATE | /* Create the environment if it does
                           * not already exist. */
    DB_INIT_TXN | /* Initialize transactions */
    DB_INIT_LOCK | /* Initialize locking. */
    DB_INIT_LOG | /* Initialize logging */
    DB_INIT_MPOOL; /* Initialize the in-memory cache. */
  ret = envp->open(envp, db_home_dir, env_flags, 0);
  if (ret != 0) {
    fprintf(stderr, "Error opening environment: %s\n",
        db_strerror(ret));
    goto err;
  }

  /* Initialize the DB handle */
  ret = db_create(&dbp, envp, 0);
  if (ret != 0) {
    envp->err(envp, ret, "Database creation failed");
    goto err;
  }

  db_flags = DB_CREATE | DB_AUTO_COMMIT;
  /*
     Open the database. Note that we are using auto commit for the open,
     so the database is able to support transactions.
     */
  ret = dbp->open(dbp, /* Pointer to the database */
      NULL, /* Txn pointer */
      file_name, /* File name */
      NULL, /* Logical db name */
      DB_BTREE, /* Database type (using btree) */
      db_flags, /* Open flags */
      0); /* File mode. Using defaults */
  if (ret != 0) {
    envp->err(envp, ret, "Database '%s' open failed",
        file_name);
    goto err;
  }

  /* Get the txn handle */
  txn = NULL;
  ret = envp->txn_begin(envp, NULL, &txn, 0);
  if (ret != 0) {
    envp->err(envp, ret, "Transaction begin failed.");
    goto err;
  }

  for (i = 0; i < LOOP_SIZE; i++) {
    /* Prepare the DBTs */
    memset(&key, 0, sizeof(DBT));
    memset(&data, 0, sizeof(DBT));

    sprintf((char*)keystr, "key%d", i);
    sprintf((char*)datastr, "data%d", i);
  
    key.data = (char*)keystr;
    key.size = strlen((char*)keystr) + 1;
    data.data = (char*)datastr;
    data.size = strlen((char*)datastr) + 1;
  
    /* Perform the database write. If this fails, abort the transaction. */
    ret = dbp->put(dbp, txn, &key, &data, 0);
    if (ret != 0) {
      envp->err(envp, ret, "Database put failed.");
      txn->abort(txn);
      goto err;
    }
  }

  /* Commit the transaction. Note that the transaction handle
     can no longer be used. */
  ret = txn->commit(txn, 0);
  if (ret != 0) {
    envp->err(envp, ret, "Transaction commit failed.");
    goto err;
  }

err:
  /* Close the database */
  if (dbp != NULL) {
    ret_c = dbp->close(dbp, 0);
    if (ret_c != 0) {
      envp->err(envp, ret_c, "Database close failed.");
      ret = ret_c;
    }
  }

  /* Close the environment */
  if (envp != NULL) {
    ret_c = envp->close(envp, 0);
    if (ret_c != 0) {
      fprintf(stderr, "environment close failed: %s\n",
          db_strerror(ret_c));
      ret = ret_c;
    }
  }

  return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
Пример #2
0
icalerrorenum icalbdbset_commit(icalset *set)
{
    DB *dbp;
    DBC *dbcp;
    DBT key, data;
    icalcomponent *c;
    char *str = NULL;
    int ret = 0;
    int reterr = ICAL_NO_ERROR;
    char keystore[256];
    char uidbuf[256];
    char datastore[1024];
    char *more_mem = NULL;
    DB_TXN *tid = NULL;
    icalbdbset *bset = (icalbdbset *) set;
    int bad_uid_counter = 0;
    int retry = 0, done = 0, completed = 0, deadlocked = 0;

    icalerror_check_arg_re((bset != 0), "bset", ICAL_BADARG_ERROR);

    dbp = bset->dbp;
    icalerror_check_arg_re((dbp != 0), "dbp is invalid", ICAL_BADARG_ERROR);

    if (bset->changed == 0) {
        return ICAL_NO_ERROR;
    }

    memset(&key, 0, sizeof(key));
    memset(&data, 0, sizeof(data));

    key.flags = DB_DBT_USERMEM;
    key.data = keystore;
    key.ulen = (u_int32_t) sizeof(keystore);

    data.flags = DB_DBT_USERMEM;
    data.data = datastore;
    data.ulen = (u_int32_t) sizeof(datastore);

    if (!ICAL_DB_ENV) {
        if (icalbdbset_init_dbenv(NULL, NULL) != 0) {
            return ICAL_INTERNAL_ERROR;
        }
    }

    while ((retry < MAX_RETRY) && !done) {

        if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
            if (ret == DB_LOCK_DEADLOCK) {
                retry++;
                continue;
            } else if (ret == DB_RUNRECOVERY) {
                ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "icalbdbset_commit: txn_begin failed");
                abort();
            } else {
                ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "icalbdbset_commit");
                return ICAL_INTERNAL_ERROR;
            }
        }

        /* first delete everything in the database, because there could be removed components */
        if ((ret = dbp->cursor(dbp, tid, &dbcp, DB_DIRTY_READ)) != 0) {
            tid->abort(tid);
            if (ret == DB_LOCK_DEADLOCK) {
                retry++;
                continue;
            } else if (ret == DB_RUNRECOVERY) {
                ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "curor failed");
                abort();
            } else {
                ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "curor failed");
                /* leave bset->changed set to true */
                return ICAL_INTERNAL_ERROR;
            }
        }

        /* fetch the key/data pair, then delete it */
        completed = 0;
        while (!completed && !deadlocked) {
            ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT);
            if (ret == DB_NOTFOUND) {
                completed = 1;
            } else if (ret == ENOMEM) {
                if (more_mem) {
                    free(more_mem);
                }
                more_mem = malloc(data.ulen + 1024);
                data.data = more_mem;
                data.ulen = data.ulen + 1024;
            } else if (ret == DB_LOCK_DEADLOCK) {
                deadlocked = 1;
            } else if (ret == DB_RUNRECOVERY) {
                tid->abort(tid);
                ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_get failed.");
                abort();
            } else if (ret == 0) {
                if ((ret = dbcp->c_del(dbcp, 0)) != 0) {
                    dbp->err(dbp, ret, "cursor");
                    if (ret == DB_KEYEMPTY) {
                        /* never actually created, continue onward.. */
                        /* do nothing - break; */
                    } else if (ret == DB_LOCK_DEADLOCK) {
                        deadlocked = 1;
                    } else {
                        /*char *foo = db_strerror(ret); */
                        abort();
                    }
                }
            } else {    /* some other non-fatal error */
                dbcp->c_close(dbcp);
                tid->abort(tid);
                if (more_mem) {
                    free(more_mem);
                    more_mem = NULL;
                }
                return ICAL_INTERNAL_ERROR;
            }
        }

        if (more_mem) {
            free(more_mem);
            more_mem = NULL;
        }

        if (deadlocked) {
            dbcp->c_close(dbcp);
            tid->abort(tid);
            retry++;
            continue;   /* next retry */
        }

        deadlocked = 0;
        for (c = icalcomponent_get_first_component(bset->cluster, ICAL_ANY_COMPONENT);
             c != 0 && !deadlocked;
             c = icalcomponent_get_next_component(bset->cluster, ICAL_ANY_COMPONENT)) {

            memset(&key, 0, sizeof(key));
            memset(&data, 0, sizeof(data));

            /* Note that we're always inserting into a primary index. */
            if (icalcomponent_isa(c) != ICAL_VAGENDA_COMPONENT) {
                char *uidstr = (char *)icalcomponent_get_uid(c);

                if (!uidstr) {  /* this shouldn't happen */
                    /* no uid string, we need to add one */
                    snprintf(uidbuf, 256, "baduid%d-%d", getpid(), bad_uid_counter++);
                    key.data = uidbuf;
                } else {
                    key.data = uidstr;
                }
            } else {
                char *relcalid = NULL;

                relcalid = (char *)icalcomponent_get_relcalid(c);
                if (relcalid == NULL) {
                    snprintf(uidbuf, 256, "baduid%d-%d", getpid(), bad_uid_counter++);
                    key.data = uidbuf;
                } else {
                    key.data = relcalid;
                }
            }
            key.size = (u_int32_t) strlen(key.data);

            str = icalcomponent_as_ical_string_r(c);
            data.data = str;
            data.size = (u_int32_t) strlen(str);

            if ((ret = dbcp->c_put(dbcp, &key, &data, DB_KEYLAST)) != 0) {
                if (ret == DB_LOCK_DEADLOCK) {
                    deadlocked = 1;
                } else if (ret == DB_RUNRECOVERY) {
                    ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_put failed.");
                    abort();
                } else {
                    ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_put failed %s.", str);
                    /* continue to try to put as many icalcomponent as possible */
                    reterr = ICAL_INTERNAL_ERROR;
                }
            }
        }

        if (str) {
            free(str);
        }

        if (deadlocked) {
            dbcp->c_close(dbcp);
            tid->abort(tid);
            retry++;
            continue;
        }

        if ((ret = dbcp->c_close(dbcp)) != 0) {
            tid->abort(tid);
            if (ret == DB_LOCK_DEADLOCK) {
                retry++;
                continue;
            } else if (ret == DB_RUNRECOVERY) {
                ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_closed failed.");
                abort();
            } else {
                ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_closed failed.");
                reterr = ICAL_INTERNAL_ERROR;
            }
        }

        if ((ret = tid->commit(tid, 0)) != 0) {
            tid->abort(tid);
            if (ret == DB_LOCK_DEADLOCK) {
                retry++;
                continue;
            } else if (ret == DB_RUNRECOVERY) {
                ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "commit failed.");
                abort();
            } else {
                ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "commit failed.");
                reterr = ICAL_INTERNAL_ERROR;
            }
        }

        done = 1;
    }

    bset->changed = 0;
    return reterr;
}
void
run_xact(DB_ENV *dbenv, DB *db, int offset, int count)
{
  //	va_list ap;
	DBC *dbc;
	DBT key, data;
	DB_TXN *tid;
	int ret;
	char *s;

	/* Initialization. */
	memset(&key, 0, sizeof(key));
	memset(&data, 0, sizeof(data));
	int keyPtr;
	int valPtr;
	key.data = &keyPtr;
	key.size = sizeof(int);/*strlen(name);*/
	data.data = &valPtr;
	data.size = sizeof(int);

retry:	/* Begin the transaction. */
	if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) {
		dbenv->err(dbenv, ret, "DB_ENV->txn_begin");
		exit (1);
	}

	/* Delete any previously existing item. */
	/*	switch (ret = db->del(db, tid, &key, 0)) {
	case 0:
	case DB_NOTFOUND:
	  break;
	case DB_LOCK_DEADLOCK:
	  abort();
	  / * Deadlock: retry the operation. * /
			  if ((ret = tid->abort(tid)) != 0) {
			    dbenv->err(dbenv, ret, "DB_TXN->abort");
			    exit (1);
			  }
			  goto retry;
	default:
	  //	  dbenv->err(dbenv, ret, "db->del: %s", name);
	  abort();
	  exit (1);
	} */
 

	/* Create a cursor. */
	/*	if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) {
		dbenv->err(dbenv, ret, "db->cursor");
		exit (1);
		} */

	int q;
	/* Count is one for this test */
	//	assert(count == 1);

	for(q = offset; q < offset + count; q++) {
	  keyPtr = q+1;
	  valPtr = q;
	  /*	  switch (ret = db->del(db, tid, &key, 0)) {
	  case 0:
	  case DB_NOTFOUND:
	    break;
	  case DB_LOCK_DEADLOCK:
	    abort();
	    // Deadlock: retry the operation. 
	    if ((ret = tid->abort(tid)) != 0) {
	      dbenv->err(dbenv, ret, "DB_TXN->abort");
	      exit (1);
	    }
	    goto retry;
	  default:
	    //	  dbenv->err(dbenv, ret, "db->del: %s", name);
	    abort();
	    exit (1);
	    } */
	  		
	  //	  pthread_mutex_lock(&hack);
	  switch (ret = db->put(db, tid, &key, &data, 0)) {
	  case 0:
	    break;
	  case DB_LOCK_DEADLOCK:
	    //		  va_end(ap);
	    abort();  // Locking should be disabled!
	    /* Deadlock: retry the operation. */
	    if ((ret = dbc->c_close(dbc)) != 0) {
	      dbenv->err(
			 dbenv, ret, "dbc->c_close");
	      exit (1);
	    }
	    if ((ret = tid->abort(tid)) != 0) {
	      dbenv->err(dbenv, ret, "DB_TXN->abort");
	      exit (1);
		  }
	    goto retry;
	  default:
	    /* Error: run recovery. */
	    dbenv->err(dbenv, ret, "dbc->put: %d/%d", q, q);
	    abort();  // Error invalidates benchmark!
	    exit (1);
	  }
	  //	  pthread_mutex_unlock(&hack);
	  putCount++;
	}
	

	if ((ret = tid->commit(tid, 0)) != 0) {
		dbenv->err(dbenv, ret, "DB_TXN->commit");
		exit (1);
	}
	commitCount++;
#ifdef DEBUG_BDB
	printf("Called commit\n");
#endif
}
Пример #4
0
nfsstat4 nfs_op_readdir(struct nfs_cxn *cxn, const READDIR4args *args,
		        struct list_head *writes, struct rpc_write **wr)
{
	nfsstat4 status = NFS4_OK;
	struct nfs_inode *ino = NULL;
	uint32_t dircount, maxcount, *status_p;
	struct readdir_info ri;
	uint64_t cookie, attr_request;
	const verifier4 *cookie_verf;
	DB_TXN *txn = NULL;
	DB *dirent = srv.fsdb.dirent;
	DB_ENV *dbenv = srv.fsdb.env;
	DBT pkey, pval;
	struct fsdb_de_key key;
	int cget_flags;
	DBC *curs = NULL;
	int rc;
	uint64_t dirent_inum, db_de;
	struct fsdb_de_key *rkey;

	cookie = args->cookie;
	cookie_verf = &args->cookieverf;
	dircount = args->dircount;
	maxcount = args->maxcount;
	attr_request = bitmap4_decode(&args->attr_request);

	status_p = WRSKIP(4);

	if (debugging) {
		applog(LOG_INFO, "op READDIR (COOKIE:%Lu DIR:%u MAX:%u MAP:%Lx)",
		       (unsigned long long) cookie,
		       dircount,
		       maxcount,
		       (unsigned long long) attr_request);

		print_fattr_bitmap("op READDIR", attr_request);
	}

	/* traditionally "." and "..", hardcoded */
	if (cookie == 1 || cookie == 2) {
		status = NFS4ERR_BAD_COOKIE;
		goto out;
	}
	/* don't permit request of write-only attrib */
	if (attr_request & fattr_write_only_mask) {
		status = NFS4ERR_INVAL;
		goto out;
	}

	/* FIXME: very, very, very poor verifier */
	if (cookie &&
	    memcmp(cookie_verf, &srv.instance_verf, sizeof(verifier4))) {
		status = NFS4ERR_NOT_SAME;
		goto out;
	}

	/* read inode of directory being read */
	status = dir_curfh(NULL, cxn, &ino, 0);
	if (status != NFS4_OK)
		goto out;
	if (ino->mode == 0) {
		status = NFS4ERR_ACCESS;
		goto out;
	}

	/* subtract READDIR4resok header and footer size */
	if (maxcount < 16) {
		status = NFS4ERR_TOOSMALL;
		goto out;
	}

	maxcount -= (8 + 4 + 4);

	/* verify within server limits */
	if (dircount > SRV_MAX_READ || maxcount > SRV_MAX_READ) {
		status = NFS4ERR_INVAL;
		goto out;
	}

	/* open transaction */
	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto out;
	}

	/* set up directory iteration */
	memset(&ri, 0, sizeof(ri));
	ri.cookie = cookie;
	ri.dircount = dircount;
	ri.maxcount = maxcount;
	ri.attr_request = attr_request;
	ri.status = NFS4_OK;
	ri.writes = writes;
	ri.wr = wr;
	ri.dir_pos = 3;
	ri.first_time = true;

	/* if dir is empty, skip directory interation loop completely */
	if (dir_is_empty(txn, ino)) {
		WRMEM(&srv.instance_verf, sizeof(verifier4));	/* cookieverf */

		ri.val_follows = WRSKIP(4);

		if (debugging)
			applog(LOG_DEBUG, "   READDIR: empty directory");

		goto the_finale;
	}

	/* otherwise, loop through each dirent attached to ino->inum */
	rc = dirent->cursor(dirent, txn, &curs, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dirent->err(dirent, rc, "dirent->cursor");
		goto out_abort;
	}

	key.inum = inum_encode(ino->inum);

	memset(&pkey, 0, sizeof(pkey));
	pkey.data = &key;
	pkey.size = sizeof(key);
	pkey.flags = DB_DBT_MALLOC;

	memset(&pval, 0, sizeof(pval));
	pval.data = &db_de;
	pval.ulen = sizeof(db_de);
	pval.flags = DB_DBT_USERMEM;

	cget_flags = DB_SET_RANGE;
	while (1) {
		bool iter_rc;

		rc = curs->get(curs, &pkey, &pval, cget_flags);
		if (rc) {
			if (rc != DB_NOTFOUND)
				dirent->err(dirent, rc, "readdir curs->get");
			break;
		}

		cget_flags = DB_NEXT;

		rkey = pkey.data;
		if (inum_decode(rkey->inum) != ino->inum) {
			free(rkey);
			break;
		}

		dirent_inum = inum_decode(db_de);

		iter_rc = readdir_iter(txn, rkey, pkey.size, dirent_inum, &ri);
		free(rkey);

		if (iter_rc)
			break;
	}

	if (!ri.n_results) {
		if (debugging)
			applog(LOG_INFO, "           zero results, status %s",
			       ri.status <= NFS4ERR_CB_PATH_DOWN ?
			       		status2str(ri.status) : "n/a");

		if (ri.status == NFS4_OK) {
			WRMEM(&srv.instance_verf, sizeof(verifier4));	/* cookieverf */

			ri.val_follows = WRSKIP(4);
		}
	}

	rc = curs->close(curs);
	if (rc) {
		status = NFS4ERR_IO;
		dirent->err(dirent, rc, "dirent->cursor close");
		goto out_abort;
	}

the_finale:

	/* terminate final entry4.nextentry and dirlist4.entries */
	if (ri.val_follows)
		*ri.val_follows = htonl(0);

	if (ri.cookie_found && !ri.n_results && ri.hit_limit) {
		status = NFS4ERR_TOOSMALL;
		goto out_abort;
	}

	/* close transaction */
	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		status = NFS4ERR_IO;
		goto out;
	}

	WR32(ri.hit_limit ? 0 : 1);		/* reply eof */

out:
	*status_p = htonl(status);
	inode_free(ino);
	return status;

out_abort:
	if (txn->abort(txn))
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	goto out;
}
Пример #5
0
bool access_list(struct client *cli, const char *bucket, const char *key,
		 const char *user)
{
	struct macl {
		char		perm[128];		/* perm(s) granted */
		char		grantee[64];		/* grantee user */
	};

	GHashTable *param;
	enum errcode err = InternalError;
	DB_ENV *dbenv = tdbrep.tdb.env;
	DB *acls = tdbrep.tdb.acls;
	int alloc_len;
	char owner[64];
	GList *res;
	struct db_acl_key *acl_key;
	struct db_acl_ent *acl;
	DB_TXN *txn = NULL;
	DBC *cur = NULL;
	GList *content;
	DBT pkey, pval;
	struct macl *mp;
	char guser[64];
	GList *p;
	char *s;
	int str_len;
	int rc;
	bool rcb;

	/* verify READ access for ACL */
	if (!user || !has_access(user, bucket, key, "READ_ACP")) {
		err = AccessDenied;
		goto err_out;
	}

	/* parse URI query string */
	param = hreq_query(&cli->req);
	if (!param)
		goto err_out;

	res = NULL;

	alloc_len = sizeof(struct db_acl_key) + strlen(key) + 1;
	acl_key = alloca(alloc_len);
	memset(acl_key, 0, alloc_len);

	strncpy(acl_key->bucket, bucket, sizeof(acl_key->bucket));
	strcpy(acl_key->key, key);

	/* open transaction, search cursor */
	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto err_out_param;
	}

	rc = bucket_find(txn, bucket, &owner[0], sizeof(owner));
	if (rc) {
		if (rc == DB_NOTFOUND)
			err = InvalidBucketName;
		else
			dbenv->err(dbenv, rc, "bucket_find");
		goto err_out_rb;
	}

	rc = acls->cursor(acls, txn, &cur, 0);
	if (rc) {
		acls->err(acls, rc, "acls->cursor");
		goto err_out_rb;
	}

	memset(&pkey, 0, sizeof(pkey));
	pkey.data = acl_key;
	pkey.size = alloc_len;

	for (;; free(acl)) {

		memset(&pval, 0, sizeof(pval));
		pval.flags = DB_DBT_MALLOC;

		rc = cur->get(cur, &pkey, &pval, DB_NEXT);
		if (rc)
			break;

		acl = pval.data;

		/* This is a workaround, see FIXME about DB_NEXT. */
		if (strncmp(acl->bucket, bucket, sizeof(acl->bucket)))
			continue;
		if (strcmp(acl->key, key))
			continue;

		if ((mp = malloc(sizeof(struct macl))) == NULL) {
			free(acl);
			cur->close(cur);
			goto err_out_rb;
		}

		memcpy(mp->grantee, acl->grantee, sizeof(mp->grantee));
		mp->grantee[sizeof(mp->grantee)-1] = 0;

		memcpy(mp->perm, acl->perm, sizeof(mp->perm));

		/* lop off the trailing comma */
		mp->perm[sizeof(mp->perm)-1] = 0;
		str_len = strlen(mp->perm);
		if (str_len && mp->perm[str_len-1] == ',')
			mp->perm[--str_len] = 0;

		res = g_list_append(res, mp);
	}

	if (rc != DB_NOTFOUND)
		acls->err(acls, rc, "access_list iteration");

	/* close cursor, transaction */
	rc = cur->close(cur);
	if (rc)
		acls->err(acls, rc, "acls->cursor close");
	rc = txn->commit(txn, 0);
	if (rc)
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");

	/* dump collected acls -- no more exception handling */

	s = g_markup_printf_escaped(
		"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
		"<AccessControlPolicy "
		     "xmlns=\"http://indy.yyz.us/doc/2006-03-01/\">\r\n"
		"  <Owner>\r\n"
		"    <ID>%s</ID>\r\n"
		"    <DisplayName>%s</DisplayName>\r\n"
		"  </Owner>\r\n",
		owner, owner);
	content = g_list_append(NULL, s);

	s = g_markup_printf_escaped(
		"  <AccessControlList>\r\n");
	content = g_list_append(content, s);

	for (p = res; p != NULL; p = p->next) {
		mp = p->data;

		if (!strcmp(DB_ACL_ANON, mp->grantee)) {
			strcpy(guser, "anonymous");
		} else {
			strncpy(guser, mp->grantee, sizeof(guser));
			guser[sizeof(guser)-1] = 0;
		}

		s = g_markup_printf_escaped(
			"    <Grant>\r\n"
			"      <Grantee xmlns:xsi=\"http://www.w3.org/2001/"
			"XMLSchema-instance\" xsi:type=\"CanonicalUser\">\r\n"
			"        <ID>%s</ID>\r\n"
			"        <DisplayName>%s</DisplayName>\r\n"
			"      </Grantee>\r\n",
			guser, guser);
		content = g_list_append(content, s);

		/*
		 * FIXME This parsing is totally lame, we should replace
		 * strings with a bit mask once we make sure this works.
		 */
		if (!strcmp(mp->perm, "READ,WRITE,READ_ACP,WRITE_ACP")) {
			s = g_markup_printf_escaped(
			   "      <Permission>FULL_CONTROL</Permission>\r\n");
		} else {
			s = g_markup_printf_escaped(
			   "      <Permission>%s</Permission>\r\n",
			   mp->perm);
		}
		content = g_list_append(content, s);

		s = g_markup_printf_escaped("    </Grant>\r\n");
		content = g_list_append(content, s);

		free(mp);
	}

	s = g_markup_printf_escaped("  </AccessControlList>\r\n");
	content = g_list_append(content, s);

	s = g_markup_printf_escaped("</AccessControlPolicy>\r\n");
	content = g_list_append(content, s);

	g_list_free(res);

	rcb = cli_resp_xml(cli, 200, content);
	g_list_free(content);
	return rcb;

err_out_rb:
	rc = txn->abort(txn);
	if (rc)
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	for (p = res; p != NULL; p = p->next)
		free(p->data);
	g_list_free(res);
err_out_param:
	g_hash_table_destroy(param);
err_out:
	return cli_err(cli, err);
}
Пример #6
0
bool bucket_add(struct client *cli, const char *user, const char *bucket)
{
	char *hdr, timestr[64];
	enum errcode err = InternalError;
	int rc;
	struct db_bucket_ent ent;
	bool setacl;			/* is ok to put pre-existing bucket */
	enum ReqACLC canacl;
	DB *buckets = tdbrep.tdb.buckets;
	DB *acls = tdbrep.tdb.acls;
	DB_ENV *dbenv = tdbrep.tdb.env;
	DB_TXN *txn = NULL;
	DBT key, val;

	if (!user)
		return cli_err(cli, AccessDenied);

	/* prepare parameters */
	setacl = false;
	if (cli->req.uri.query_len) {
		switch (hreq_is_query(&cli->req)) {
		case URIQ_ACL:
			setacl = true;
			break;
		default:
			err = InvalidURI;
			goto err_par;
		}
	}

	if ((rc = hreq_acl_canned(&cli->req)) == ACLCNUM) {
		err = InvalidArgument;
		goto err_par;
	}
	canacl = (rc == -1)? ACLC_PRIV: rc;

	/* begin trans */
	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto err_db;
	}

	memset(&key, 0, sizeof(key));
	memset(&val, 0, sizeof(val));
	memset(&ent, 0, sizeof(ent));
	strncpy(ent.name, bucket, sizeof(ent.name));
	strncpy(ent.owner, user, sizeof(ent.owner));
	ent.time_create = GUINT64_TO_LE(time(NULL));

	key.data = &ent.name;
	key.size = strlen(ent.name) + 1;

	val.data = &ent;
	val.size = sizeof(ent);

	if (setacl) {
		/* check if the bucket exists, else insert it */
		rc = bucket_find(txn, bucket, NULL, 0);
		if (rc) {
			if (rc != DB_NOTFOUND) {
				buckets->err(buckets, rc, "buckets->find");
				goto err_out;
			}

			rc = buckets->put(buckets, txn, &key, &val,
							DB_NOOVERWRITE);
			if (rc) {
				buckets->err(buckets, rc, "buckets->put");
				goto err_out;
			}
		} else {
			if (!has_access(user, bucket, NULL, "WRITE_ACP")) {
				err = AccessDenied;
				goto err_out;
			}
			if (!object_del_acls(txn, bucket, ""))
				goto err_out;
		}

	} else {
		/* attempt to insert new bucket */
		rc = buckets->put(buckets, txn, &key, &val, DB_NOOVERWRITE);
		if (rc) {
			if (rc == DB_KEYEXIST)
				err = BucketAlreadyExists;
			else
				buckets->err(buckets, rc, "buckets->put");
			goto err_out;
		}
	}

	/* insert bucket ACL */
	rc = add_access_canned(txn, bucket, "", user, canacl);
	if (rc) {
		acls->err(acls, rc, "acls->put");
		goto err_out;
	}

	/* commit -- no more exception emulation with goto. */
	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		return cli_err(cli, InternalError);
	}

	if (asprintf(&hdr,
"HTTP/%d.%d 200 x\r\n"
"Content-Length: 0\r\n"
"Date: %s\r\n"
"Location: /%s\r\n"
"Server: " PACKAGE_STRING "\r\n"
"\r\n",
		     cli->req.major,
		     cli->req.minor,
		     hutil_time2str(timestr, sizeof(timestr), time(NULL)),
		     bucket) < 0)
		return cli_err(cli, InternalError);

	rc = atcp_writeq(&cli->wst, hdr, strlen(hdr), atcp_cb_free, hdr);
	if (rc) {
		free(hdr);
		return true;
	}

	return atcp_write_start(&cli->wst);

err_out:
	rc = txn->abort(txn);
	if (rc)
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
err_db:
err_par:
	return cli_err(cli, err);
}
Пример #7
0
/* 批量插入示例函数。*/
void *
run_bulk_delete()
{
    int raw_key[NUM_KEY_INT];
    DBT key;
    DB_ENV *envp;
    int bulk_size = 100;
    DB *dbp;
    DB_TXN *tid;
    int *delete_load;
    int delete_count, i, ret, op_flag;

    char *key_buf;
    void *p;
    int j;

    /* Initialize structs and arrays */
    memset(raw_key, 0, KEY_SIZE);
    memset(&key, 0, sizeof(DBT));
    tid = NULL;

    /*
     * 初始化批量删除使用的key buffer。由于批量删除不需要data,
     * 所以只需要初始化和填充key buffer。我们同样需要使用自己分配的内存。
     */
    key_buf = (char*) malloc(KEY_SIZE * bulk_size * 2);
    memset(key_buf, 0, KEY_SIZE * bulk_size * 2);

    /* 初始化key buffer DBT 对象,设置正确的flags和ulen成员。 */
    key.data = key_buf;
    key.ulen = KEY_SIZE * bulk_size * 2;
    key.flags = DB_DBT_USERMEM;
    op_flag = DB_MULTIPLE; /* 批量删除同样需要这个flag。*/

    /*
     * 批量删除所有的数据。每一批删除由key buffer DBT 当中的key
     * 指定的bulk_size条key/data pair. 这两个宏的详细用法见上文。
     */
    for (i = 0; i < delete_count / bulk_size; ) {
        /* 为批量删除初始化并填充一个key buffer DBT 对象。 */
        DB_MULTIPLE_WRITE_INIT(p, &key);
        for (j = i * bulk_size; j < (i + 1) * bulk_size; j++) {
            raw_key[0] = delete_load[j];
            DB_MULTIPLE_WRITE_NEXT(p, &key, raw_key, KEY_SIZE);
        }
        /* 启动事务。*/
        if ((ret = envp->txn_begin(envp, NULL, &tid, 0)) != 0) {
            envp->err(envp, ret, "[delete] DB_ENV->txn_begin");
            exit(EXIT_FAILURE);
        }

        /*
         * 执行批量删除。key buffer DBT
         * 当中的bulk_size条key指定的key/data pairs会被从数据库当中删除。
         */
        switch(ret = dbp->del(dbp, tid, &key, op_flag)) {
        case 0: /* 批量删除操作成功,提交事务。*/
            if ((ret = tid->commit(tid, 0)) != 0) {
                envp->err(envp, ret, "[delete] DB_TXN->commit");
                exit(EXIT_FAILURE);
            }
            break;
        case DB_LOCK_DEADLOCK:
            /* 如果数据库操作发生死锁,那么必须abort事务。然后,可以选择重新执行该操作。*/
            if ((ret = tid->abort(tid)) != 0) {
                envp->err(envp, ret, "[delete] DB_TXN->abort");
                exit(EXIT_FAILURE);
            }
            continue;
        default:
            envp->err(envp, ret, "[delete] DB->del ([%d]%d)", i, delete_load[i]);
            exit(EXIT_FAILURE);
        }
        i++;
    }

    (void)free(key_buf);

    return (NULL);
}
Пример #8
0
/*
 * A function that performs a series of writes to a
 * Berkeley DB database. The information written
 * to the database is largely nonsensical, but the
 * mechanism of transactional commit/abort and
 * deadlock detection is illustrated here.
 */
void *
writer_thread(void *args)
{
    static char *key_strings[] = {
	"key 1", "key 2", "key 3", "key 4", "key 5",
	"key 6", "key 7", "key 8", "key 9", "key 10"
    };
    DB *dbp;
    DB_ENV *envp;
    DBT key, value;
    DB_TXN *txn;
    int i, j, payload, ret, thread_num;
    int retry_count, max_retries = 20;   /* Max retry on a deadlock */

    dbp = (DB *)args;
    envp = dbp->get_env(dbp);

    /* Get the thread number */
    (void)mutex_lock(&thread_num_lock);
    global_thread_num++;
    thread_num = global_thread_num;
    (void)mutex_unlock(&thread_num_lock);

    /* Initialize the random number generator */
    srand(thread_num);

    /* Write 50 times and then quit */
    for (i = 0; i < 50; i++) {
	retry_count = 0; /* Used for deadlock retries */

	/*
	 * Some think it is bad form to loop with a goto statement, but
	 * we do it anyway because it is the simplest and clearest way
	 * to achieve our abort/retry operation.
	 */
retry:
	/* Begin our transaction. We group multiple writes in
	 * this thread under a single transaction so as to
	 * (1) show that you can atomically perform multiple writes
	 * at a time, and (2) to increase the chances of a
	 * deadlock occurring so that we can observe our
	 * deadlock detection at work.
	 *
	 * Normally we would want to avoid the potential for deadlocks,
	 * so for this workload the correct thing would be to perform our
	 * puts with autocommit. But that would excessively simplify our
	 * example, so we do the "wrong" thing here instead.
	 */
	ret = envp->txn_begin(envp, NULL, &txn, 0);
	if (ret != 0) {
	    envp->err(envp, ret, "txn_begin failed");
	    return ((void *)EXIT_FAILURE);
	}
	for (j = 0; j < 10; j++) {
	    /* Set up our key and values DBTs */
	    memset(&key, 0, sizeof(DBT));
	    key.data = key_strings[j];
	    key.size = (u_int32_t)strlen(key_strings[j]) + 1;

	    memset(&value, 0, sizeof(DBT));
	    payload = rand() + i;
	    value.data = &payload;
	    value.size = sizeof(int);

	    /* Perform the database put. */
	    switch (ret = dbp->put(dbp, txn, &key, &value, 0)) {
		case 0:
		    break;

		/*
		 * Here's where we perform deadlock detection. If
		 * DB_LOCK_DEADLOCK is returned by the put operation,
		 * then this thread has been chosen to break a deadlock.
		 * It must abort its operation, and optionally retry the
		 * put.
		 */
		case DB_LOCK_DEADLOCK:
		    /*
		     * First thing that we MUST do is abort the
		     * transaction.
		     */
		    (void)txn->abort(txn);
		    /*
		     * Now we decide if we want to retry the operation.
		     * If we have retried less than max_retries,
		     * increment the retry count and goto retry.
		     */
		    if (retry_count < max_retries) {
			printf("Writer %i: Got DB_LOCK_DEADLOCK.\n",
			    thread_num);
			printf("Writer %i: Retrying write operation.\n",
			    thread_num);
			retry_count++;
			goto retry;
		    }
		    /*
		     * Otherwise, just give up.
		     */
		    printf("Writer %i: ", thread_num);
		    printf("Got DB_LOCK_DEADLOCK and out of retries.\n");
		    printf("Writer %i: Giving up.\n", thread_num);
		    return ((void *)EXIT_FAILURE);
		/*
		 * If a generic error occurs, we simply abort the
		 * transaction and exit the thread completely.
		 */
		default:
		    envp->err(envp, ret, "db put failed");
		    ret = txn->abort(txn);
		    if (ret != 0)
			envp->err(envp, ret, "txn abort failed");
		    return ((void *)EXIT_FAILURE);
	     } /** End case statement **/

	}   /** End for loop **/

	/*
	 * print the number of records found in the database.
	 * See count_records() for usage information.
	 */
	printf("Thread %i. Record count: %i\n", thread_num,
	    count_records(dbp, txn));

	/*
	 * If all goes well, we can commit the transaction and
	 * exit the thread.
	 */
	ret = txn->commit(txn, 0);
	if (ret != 0) {
	    envp->err(envp, ret, "txn commit failed");
	    return ((void *)EXIT_FAILURE);
	}
    }
    return ((void *)EXIT_SUCCESS);
}
Пример #9
0
void
add_cat(DB_ENV *dbenv, DB *db, char *name, ...)
{
	va_list ap;
	DBC *dbc;
	DBT key, data;
	DB_TXN *tid;
	int ret;
	char *s;

	/* Initialization. */
	memset(&key, 0, sizeof(key));
	memset(&data, 0, sizeof(data));
	key.data = name;
	key.size = strlen(name);

retry:	/* Begin the transaction. */
	if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) {
		dbenv->err(dbenv, ret, "DB_ENV->txn_begin");
		exit (1);
	}

	/* Delete any previously existing item. */
	switch (ret = db->del(db, tid, &key, 0)) {
	case 0:
	case DB_NOTFOUND:
		break;
	case DB_LOCK_DEADLOCK:
		/* Deadlock: retry the operation. */
		if ((ret = tid->abort(tid)) != 0) {
			dbenv->err(dbenv, ret, "DB_TXN->abort");
			exit (1);
		}
		goto retry;
	default:
		dbenv->err(dbenv, ret, "db->del: %s", name);
		exit (1);
	}

	/* Create a cursor. */
	if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) {
		dbenv->err(dbenv, ret, "db->cursor");
		exit (1);
	}

	/* Append the items, in order. */
	va_start(ap, name);
	while ((s = va_arg(ap, char *)) != NULL) {
		data.data = s;
		data.size = strlen(s);
		switch (ret = dbc->c_put(dbc, &key, &data, DB_KEYLAST)) {
		case 0:
			break;
		case DB_LOCK_DEADLOCK:
			va_end(ap);

			/* Deadlock: retry the operation. */
			if ((ret = dbc->c_close(dbc)) != 0) {
				dbenv->err(
				    dbenv, ret, "dbc->c_close");
				exit (1);
			}
			if ((ret = tid->abort(tid)) != 0) {
				dbenv->err(dbenv, ret, "DB_TXN->abort");
				exit (1);
			}
			goto retry;
		default:
			/* Error: run recovery. */
			dbenv->err(dbenv, ret, "dbc->put: %s/%s", name, s);
			exit (1);
		}
	}
	va_end(ap);

	/* Success: commit the change. */
	if ((ret = dbc->c_close(dbc)) != 0) {
		dbenv->err(dbenv, ret, "dbc->c_close");
		exit (1);
	}
	if ((ret = tid->commit(tid, 0)) != 0) {
		dbenv->err(dbenv, ret, "DB_TXN->commit");
		exit (1);
	}
}
Пример #10
0
void
run_xact(DB_ENV *dbenv, DB *db, int offset, int count)
{
	va_list ap;
	DBC *dbc;
	DBT key, data;
	DB_TXN *tid;
	int ret;
	char *s;

	/* Initialization. */
	memset(&key, 0, sizeof(key));
	memset(&data, 0, sizeof(data));
	int keyPtr;
	int valPtr;
	key.data = &keyPtr;
	key.size = sizeof(int);/*strlen(name);*/
	data.data = &valPtr;
	data.size = sizeof(int);

retry:	/* Begin the transaction. */
	if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) {
		dbenv->err(dbenv, ret, "DB_ENV->txn_begin");
		exit (1);
	}

	/* Delete any previously existing item. */
	/*	switch (ret = db->del(db, tid, &key, 0)) {
	case 0:
	case DB_NOTFOUND:
		break;
	case DB_LOCK_DEADLOCK:
		/ * Deadlock: retry the operation. * /
		if ((ret = tid->abort(tid)) != 0) {
			dbenv->err(dbenv, ret, "DB_TXN->abort");
			exit (1);
		}
		goto retry;
	default:
		dbenv->err(dbenv, ret, "db->del: %s", name);
		exit (1);
		} */
 
	/* Create a cursor. */
	if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) {
		dbenv->err(dbenv, ret, "db->cursor");
		exit (1);
	}

	/* Append the items, in order. */
	//	va_start(ap, name);
	//	while ((s = va_arg(ap, char *)) != NULL) {
	int q;
	for(q = offset; q < offset + count; q++) {
	  keyPtr = q;
	  valPtr = q;
	  /*		data.data = s;
			data.size = strlen(s); */
	  //	  printf("A"); fflush(NULL);
		switch (ret = dbc->c_put(dbc, &key, &data, DB_KEYLAST)) {
		case 0:
		  //		  printf("B"); fflush(NULL);
			break;
		case DB_LOCK_DEADLOCK:
			va_end(ap);

			/* Deadlock: retry the operation. */
			if ((ret = dbc->c_close(dbc)) != 0) {
				dbenv->err(
				    dbenv, ret, "dbc->c_close");
				exit (1);
			}
			if ((ret = tid->abort(tid)) != 0) {
				dbenv->err(dbenv, ret, "DB_TXN->abort");
				exit (1);
			}
			goto retry;
		default:
			/* Error: run recovery. */
			dbenv->err(dbenv, ret, "dbc->put: %d/%d", q, q);
			exit (1);
		}
	}
	va_end(ap);

	/* Success: commit the change. */
	if ((ret = dbc->c_close(dbc)) != 0) {
		dbenv->err(dbenv, ret, "dbc->c_close");
		exit (1);
	}
	if ((ret = tid->commit(tid, 0)) != 0) {
		dbenv->err(dbenv, ret, "DB_TXN->commit");
		exit (1);
	}
}
Пример #11
0
void
add_color(DB_ENV *dbenv, DB *dbp, char *color, int increment)
{
	DBT key, data;
	DB_TXN *tid;
	int original, ret;
	char buf[64];

	/* Initialization. */
	memset(&key, 0, sizeof(key));
	key.data = color;
	key.size = strlen(color);
	memset(&data, 0, sizeof(data));
	data.flags = DB_DBT_MALLOC;

	for (;;) {
		/* Begin the transaction. */
		if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) {
			dbenv->err(dbenv, ret, "DB_ENV->txn_begin");
			exit (1);
		}

		/*
		 * Get the key.  If it exists, we increment the value.  If it
		 * doesn't exist, we create it.
		 */
		switch (ret = dbp->get(dbp, tid, &key, &data, 0)) {
		case 0:
			original = atoi(data.data);
			break;
		case DB_LOCK_DEADLOCK:
			/* Deadlock: retry the operation. */
			if ((ret = tid->abort(tid)) != 0) {
				dbenv->err(dbenv, ret, "DB_TXN->abort");
				exit (1);
			}
			continue;
		case DB_NOTFOUND:
			original = 0;
			break;
		default:
			/* Error: run recovery. */
			dbenv->err(
			    dbenv, ret, "dbc->get: %s/%d", color, increment);
			exit (1);
		}
		if (data.data != NULL)
			free(data.data);

		/* Create the new data item. */
		(void)snprintf(buf, sizeof(buf), "%d", original + increment);
		data.data = buf;
		data.size = strlen(buf) + 1;

		/* Store the new value. */
		switch (ret = dbp->put(dbp, tid, &key, &data, 0)) {
		case 0:
			/* Success: commit the change. */
			if ((ret = tid->commit(tid, 0)) != 0) {
				dbenv->err(dbenv, ret, "DB_TXN->commit");
				exit (1);
			}
			return;
		case DB_LOCK_DEADLOCK:
			/* Deadlock: retry the operation. */
			if ((ret = tid->abort(tid)) != 0) {
				dbenv->err(dbenv, ret, "DB_TXN->abort");
				exit (1);
			}
			break;
		default:
			/* Error: run recovery. */
			dbenv->err(
			    dbenv, ret, "dbc->put: %s/%d", color, increment);
			exit (1);
		}
	}
}
Пример #12
0
int
b_txn(int argc, char *argv[])
{
	extern char *optarg;
	extern int optind;
	DB_ENV *dbenv;
	DB_TXN *txn;
	int tabort, ch, i, count;

	count = 1000;
	tabort = 0;
	while ((ch = getopt(argc, argv, "ac:")) != EOF)
		switch (ch) {
		case 'a':
			tabort = 1;
			break;
		case 'c':
			count = atoi(optarg);
			break;
		case '?':
		default:
			return (usage());
		}
	argc -= optind;
	argv += optind;
	if (argc != 0)
		return (usage());

	/* Create the environment. */
	DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0);
	dbenv->set_errfile(dbenv, stderr);
#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 1
	DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR,
	    NULL, DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG |
	    DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE, 0666) == 0);
#else
	DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR,
	    DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG |
	    DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE, 0666) == 0);
#endif

	/* Start and commit/abort a transaction count times. */
	TIMER_START;
	if (tabort)
		for (i = 0; i < count; ++i) {
#if DB_VERSION_MAJOR < 4
			DB_BENCH_ASSERT(txn_begin(dbenv, NULL, &txn, 0) == 0);
			DB_BENCH_ASSERT(txn_abort(txn) == 0);
#else
			DB_BENCH_ASSERT(
			    dbenv->txn_begin(dbenv, NULL, &txn, 0) == 0);
			DB_BENCH_ASSERT(txn->abort(txn) == 0);
#endif
		}
	else
		for (i = 0; i < count; ++i) {
#if DB_VERSION_MAJOR < 4
			DB_BENCH_ASSERT(txn_begin(dbenv, NULL, &txn, 0) == 0);
			DB_BENCH_ASSERT(txn_commit(txn, 0) == 0);
#else
			DB_BENCH_ASSERT(
			    dbenv->txn_begin(dbenv, NULL, &txn, 0) == 0);
			DB_BENCH_ASSERT(txn->commit(txn, 0) == 0);
#endif
		}
	TIMER_STOP;

	printf("# %d empty transaction start/%s pairs\n",
	    count, tabort ? "abort" : "commit");
	TIMER_DISPLAY(count);

	DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0);

	return (0);
}
Пример #13
0
int next_counter(DB_ENV *env, DB *db, DB_TXN *parent,
		 unsigned char *key, u_int32_t key_size,
		 unsigned char *lockid, u_int32_t lockid_size) {
  DB_LOCK lock;
  DBT DBTKey, DBTData; 
  DB_TXN *tid; 
  int counter, tries, ret, t_ret, lockheld;
  u_int32_t id;

  /* Initialization. */ 
  memset(&lock, 0, sizeof(lock)); 
  memset(&DBTKey, 0, sizeof(DBTKey)); 
  memset(&DBTData, 0, sizeof(DBTData)); 
  DBTKey.data = key;
  DBTKey.size = key_size;
  DBTData.data = lockid;
  DBTData.size = lockid_size;

  tries = 0;

 loop:
  lockheld = 0;

  /* Begin the transaction. */ 
  if ((ret = env->txn_begin(env, parent, &tid, 0)) != 0) { 
    env->err(env, ret, "DB_ENV->txn_begin"); 
    return (-1); 
  }

  id = tid->id(tid);

  if ((ret = env->lock_get(env, id, 0, &DBTData, DB_LOCK_WRITE, &lock)) != 0)
    goto fail;

  lockheld = 1;

  memset(&DBTData, 0, sizeof(DBTData)); 
  DBTData.data = &counter;
  DBTData.ulen = sizeof(counter);
  DBTData.flags |= DB_DBT_USERMEM;

  if ((ret = db->get(db, tid, &DBTKey, &DBTData, 0)) != 0) 
    goto fail;

  ++counter;

  memset(&DBTData, 0, sizeof(DBTData)); 
  DBTData.data = &counter;
  DBTData.size = sizeof(counter);

  if ((ret = db->put(db, tid, &DBTKey, &DBTData, 0)) != 0) 
    goto fail;

  if ((ret = env->lock_put(env, &lock)) != 0) 
    goto fail;

  if ((ret = tid->commit(tid, DB_TXN_NOSYNC)) != 0) { 
    env->err(env, ret, "DB_TXN->commit"); 
    return (-2); 
  } 
  return (counter); 


 fail:
  if (lockheld)
    if ((ret = env->lock_put(env, &lock)) != 0) 
      return (-3);

  /* Abort and retry the operation. */ 
  if ((t_ret = tid->abort(tid)) != 0) { 
    env->err(env, t_ret, "DB_TXN->abort"); 
    return (-4);
  } 
  if (tries++ == 100)
    return (-5); 
  goto loop;
}
void *
writer_thread(void *args)
{
	DB *dbp;
	DB_ENV *dbenv;
	DBT key, data;
	DB_TXN *txn;

	char *key_strings[] = {"001", "002", "003", "004", "005",
	    "006", "007", "008", "009", "010"};
	int i, j, payload, ret, thread_num;
	int retry_count, max_retries = 20;

	dbp = (DB *)args;
	dbenv = dbp->dbenv;

	/* Get the thread number */
	(void)mutex_lock(&thread_num_lock);
	global_thread_num++;
	thread_num = global_thread_num;
	(void)mutex_unlock(&thread_num_lock);

	/* Initialize the random number generator */
	srand(thread_num);

	/* Write 50 times and then quit */
	for (i = 0; i < 50; i++) {
		retry_count = 0; /* Used for deadlock retries */
retry:
		ret = dbenv->txn_begin(dbenv, NULL, &txn, 0);
		if (ret != 0) {
			dbenv->err(dbenv, ret, "txn_begin failed");
			return ((void *)EXIT_FAILURE);
		}

		memset(&key, 0, sizeof(DBT));
		memset(&data, 0, sizeof(DBT));
		for (j = 0; j < 10; j++) {
			/* Set up our key and data DBTs. */
			data.data = key_strings[j];
			data.size = (u_int32_t)strlen(key_strings[j]) + 1;

			payload = rand() + i;
			key.data = &payload;
			key.size = sizeof(int);

			switch (ret = dbp->put(dbp, txn, &key, &data,
			    DB_NOOVERWRITE)) {
			case 0:
				break;
			case DB_KEYEXIST:
				break;
			case DB_LOCK_DEADLOCK:
				(void)txn->abort(txn);
				if (retry_count < max_retries) {
					retry_count++;
					goto retry;
				}
				return ((void *)EXIT_FAILURE);
			default:
				dbenv->err(dbenv, ret, "db put failed");
				ret = txn->abort(txn);

				if (ret != 0)
					dbenv->err(dbenv, ret,
					    "txn abort failed");
				return ((void *)EXIT_FAILURE);
			}
		}

		if ((ret = txn->commit(txn, 0)) != 0) {
			dbenv->err(dbenv, ret, "txn commit failed");
			return ((void *)EXIT_FAILURE);
		}
	}
	return ((void *)EXIT_SUCCESS);
}
Пример #15
0
nfsstat4 nfs_op_lookup(struct nfs_cxn *cxn, const LOOKUP4args *args,
		       struct list_head *writes, struct rpc_write **wr)
{
	nfsstat4 status = NFS4_OK;
	struct nfs_inode *ino = NULL;
	bool printed = false;
	struct nfs_buf objname;
	nfsino_t inum;
	DB_TXN *txn = NULL;
	DB_ENV *dbenv = srv.fsdb.env;
	int rc;

	objname.len = args->objname.utf8string_len;
	objname.val = args->objname.utf8string_val;

	if (!objname.len) {
		status = NFS4ERR_INVAL;
		goto out;
	}
	if (!objname.val) {
		status = NFS4ERR_BADXDR;
		goto out;
	}

	if (objname.len > SRV_MAX_NAME) {
		status = NFS4ERR_NAMETOOLONG;
		goto out;
	}

	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto out;
	}

	status = dir_curfh(txn, cxn, &ino, 0);
	if (status != NFS4_OK) {
		if ((status == NFS4ERR_NOTDIR) &&
		    (ino->type == NF4LNK))
			status = NFS4ERR_SYMLINK;
		goto out_abort;
	}

	status = dir_lookup(txn, ino, &objname, 0, &inum);
	if (status != NFS4_OK)
		goto out_abort;

	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		status = NFS4ERR_IO;
		goto out;
	}

	fh_set(&cxn->current_fh, inum);

	if (debugging) {
		applog(LOG_INFO, "op LOOKUP ('%.*s') -> %016llX",
		       objname.len,
		       objname.val,
		       (unsigned long long) cxn->current_fh.inum);
		printed = true;
	}

out:
	if (!printed) {
		if (debugging)
			applog(LOG_INFO, "op LOOKUP ('%.*s')",
			       objname.len,
			       objname.val);
	}

	WR32(status);
	inode_free(ino);
	return status;

out_abort:
	if (txn->abort(txn))
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	goto out;
}
Пример #16
0
//
// XXX Figure out the appropriate way to pick out IDs.
//
int
TpcbExample::txn(DB *adb, DB *bdb, DB *tdb, DB *hdb,
		 int accounts, int branches, int tellers)
{
	DBC *acurs, *bcurs, *tcurs;
	DB_TXN *t;
	DBT d_dbt, d_histdbt, k_dbt, k_histdbt;

	db_recno_t key;
	Defrec rec;
	Histrec hrec;
	int account, branch, teller, ret;

	memset(&d_dbt, 0, sizeof(d_dbt));
	memset(&d_histdbt, 0, sizeof(d_histdbt));
	memset(&k_dbt, 0, sizeof(k_dbt));
	memset(&k_histdbt, 0, sizeof(k_histdbt));
	k_histdbt.data = &key;
	k_histdbt.size = sizeof(key);

	// !!!
	// This is sample code -- we could move a lot of this into the driver
	// to make it faster.
	//
	account = randomId(ACCOUNT, accounts, branches, tellers);
	branch = randomId(BRANCH, accounts, branches, tellers);
	teller = randomId(TELLER, accounts, branches, tellers);

	k_dbt.size = sizeof(int);

	d_dbt.flags |= DB_DBT_USERMEM;
	d_dbt.data = &rec;
	d_dbt.ulen = sizeof(rec);

	hrec.aid = account;
	hrec.bid = branch;
	hrec.tid = teller;
	hrec.amount = 10;
	// Request 0 bytes since we're just positioning.
	d_histdbt.flags |= DB_DBT_PARTIAL;

	// START PER-TRANSACTION TIMING.
	//
	// Technically, TPCB requires a limit on response time, you only get
	// to count transactions that complete within 2 seconds.  That's not
	// an issue for this sample application -- regardless, here's where
	// the transaction begins.
	if (dbenv->txn_begin(dbenv, NULL, &t, 0) != 0)
		goto err;

	if (adb->cursor(adb, t, &acurs, 0) != 0 ||
	    bdb->cursor(bdb, t, &bcurs, 0) != 0 ||
	    tdb->cursor(tdb, t, &tcurs, 0) != 0)
		goto err;

	// Account record
	k_dbt.data = &account;
	if (acurs->get(acurs, &k_dbt, &d_dbt, DB_SET) != 0)
		goto err;
	rec.balance += 10;
	if (acurs->put(acurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
		goto err;

	// Branch record
	k_dbt.data = &branch;
	if (bcurs->get(bcurs, &k_dbt, &d_dbt, DB_SET) != 0)
		goto err;
	rec.balance += 10;
	if (bcurs->put(bcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
		goto err;

	// Teller record
	k_dbt.data = &teller;
	if (tcurs->get(tcurs, &k_dbt, &d_dbt, DB_SET) != 0)
		goto err;
	rec.balance += 10;
	if (tcurs->put(tcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
		goto err;

	// History record
	d_histdbt.flags = 0;
	d_histdbt.data = &hrec;
	d_histdbt.ulen = sizeof(hrec);
	if (hdb->put(hdb, t, &k_histdbt, &d_histdbt, DB_APPEND) != 0)
		goto err;

	if (acurs->close(acurs) != 0 || bcurs->close(bcurs) != 0
	    || tcurs->close(tcurs) != 0)
		goto err;

	ret = t->commit(t, 0);
	t = NULL;
	if (ret != 0)
		goto err;

	// END PER-TRANSACTION TIMING.
	return (0);

err:
	if (acurs != NULL)
		(void)acurs->close(acurs);
	if (bcurs != NULL)
		(void)bcurs->close(bcurs);
	if (tcurs != NULL)
		(void)tcurs->close(tcurs);
	if (t != NULL)
		(void)t->abort(t);

	return (-1);
}
Пример #17
0
nfsstat4 nfs_op_link(struct nfs_cxn *cxn, const LINK4args *args,
		     struct list_head *writes, struct rpc_write **wr)
{
	nfsstat4 status;
	struct nfs_inode *dir_ino = NULL, *src_ino = NULL;
	struct nfs_buf newname;
	uint64_t before = 0, after = 0;
	DB_TXN *txn;
	DB_ENV *dbenv = srv.fsdb.env;
	int rc;

	newname.len = args->newname.utf8string_len;
	newname.val = args->newname.utf8string_val;

	if (debugging)
		applog(LOG_INFO, "op LINK (%.*s)",
		       newname.len,
		       newname.val);

	/* verify input parameters */
	if (!valid_fh(cxn->current_fh) || !valid_fh(cxn->save_fh)) {
		status = NFS4ERR_NOFILEHANDLE;
		goto out;
	}
	if (newname.len > SRV_MAX_NAME) {
		status = NFS4ERR_NAMETOOLONG;
		goto out;
	}

	/* open transaction */
	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto out;
	}

	/* read source inode's directory inode */
	dir_ino = inode_fhdec(txn, cxn->current_fh, 0);
	if (!dir_ino) {
		status = NFS4ERR_NOFILEHANDLE;
		goto out_abort;
	}

	/* make sure target is a directory */
	if (dir_ino->type != NF4DIR) {
		status = NFS4ERR_NOTDIR;
		goto out_abort;
	}

	/* read source inode */
	src_ino = inode_fhdec(txn, cxn->save_fh, 0);
	if (!src_ino) {
		status = NFS4ERR_NOFILEHANDLE;
		goto out_abort;
	}

	/* make sure source is a not a directory */
	if (src_ino->type == NF4DIR) {
		status = NFS4ERR_ISDIR;
		goto out_abort;
	}

	before = dir_ino->version;

	/* add directory entry */
	status = dir_add(txn, dir_ino, &newname, src_ino);
	if (status != NFS4_OK)
		goto out_abort;

	after = dir_ino->version;

	/* update source inode */
	src_ino->n_link++;
	if (inode_touch(txn, src_ino)) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	/* close transaction */
	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		status = NFS4ERR_IO;
		goto out;
	}

out:
	WR32(status);
	if (status == NFS4_OK) {
		WR32(1);		/* cinfo.atomic */
		WR64(before);		/* cinfo.before */
		WR64(after);		/* cinfo.after */
	}
	inode_free(src_ino);
	inode_free(dir_ino);
	return status;

out_abort:
	if (txn->abort(txn))
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	goto out;
}
Пример #18
0
/*
 * _Index_init: initialize a new Index object.
 *
 * callspec: Index.__init__(env, name)
 * parameters:
 *  env (Env): A Env object to use as the environment
 *  name (string): The name of the Index
 * returns: 0 if initialization succeeded, otherwise -1
 * exceptions:
 *  terane.outputs.store.backend.Error: failed to create/open the Index
 */
static int
_Index_init (terane_Index *self, PyObject *args, PyObject *kwds)
{
    char *tocname = NULL;
    DB_TXN *txn = NULL;
    DB_BTREE_STAT *stats = NULL;
    int dbret;
    
    /* __init__ has already been called, don't repeat initialization */
    if (self->env != NULL)
        return 0;
    /* parse constructor parameters */
    if (!PyArg_ParseTuple (args, "O!O!", 
        &terane_EnvType, &self->env, &PyString_Type, &self->name))
        goto error;
    Py_INCREF (self->env);
    Py_INCREF (self->name);

    /* allocate a buffer with the full index toc name */
    tocname = PyMem_Malloc (PyString_Size (self->name) + 5);
    if (tocname == NULL) {
        PyErr_NoMemory ();
        goto error;
    }
    sprintf (tocname, "%s.toc", PyString_AsString (self->name));

    /* wrap db creation in a transaction */
    dbret = self->env->env->txn_begin (self->env->env, NULL, &txn, 0);
    if (dbret != 0) {
        PyErr_Format (terane_Exc_Error, "Failed to create DB_TXN handle: %s",
            db_strerror (dbret));
        goto error;
    }

    /* create the DB handle for the metadata store */
    dbret = db_create (&self->metadata, self->env->env, 0);
    if (dbret != 0) {
        PyErr_Format (terane_Exc_Error, "Failed to create handle for metadata: %s",
            db_strerror (dbret));
        goto error;
    }
    /* set compare function */
    self->metadata->set_bt_compare (self->metadata, _terane_msgpack_DB_compare);
    /* open the metadata store */
    dbret = self->metadata->open (self->metadata, txn, tocname, "metadata",
        DB_BTREE, DB_CREATE | DB_THREAD | DB_MULTIVERSION, 0);
    if (dbret != 0) {
        PyErr_Format (terane_Exc_Error, "Failed to open metadata: %s",
            db_strerror (dbret));
        goto error;
    }

    /* create the DB handle for the schema store */
    dbret = db_create (&self->schema, self->env->env, 0);
    if (dbret != 0) {
        PyErr_Format (terane_Exc_Error, "Failed to create handle for schema: %s",
            db_strerror (dbret));
        goto error;
    }
    /* set compare function */
    self->schema->set_bt_compare (self->schema, _terane_msgpack_DB_compare);
    /* open the schema store */
    dbret = self->schema->open (self->schema, txn, tocname, "schema",
        DB_BTREE, DB_CREATE | DB_THREAD | DB_MULTIVERSION, 0);
    if (dbret != 0) {
        PyErr_Format (terane_Exc_Error, "Failed to open schema: %s",
            db_strerror (dbret));
        goto error;
    }
    /* get an initial count of fields */
    dbret = self->schema->stat (self->schema, txn, &stats, 0);
    if (dbret != 0) {
        if (stats)
            PyMem_Free (stats);
        PyErr_Format (terane_Exc_Error, "Failed to get field count: %s",
            db_strerror (dbret));
        goto error;
    }
    self->nfields = (unsigned long) stats->bt_nkeys;
    if (stats)
        PyMem_Free (stats);
    stats = NULL;

    /* create the DB handle for the segments store */
    dbret = db_create (&self->segments, self->env->env, 0);
    if (dbret != 0) {
        PyErr_Format (terane_Exc_Error, "Failed to create handle for segments: %s",
            db_strerror (dbret));
        goto error;
    }
    /* open the segments store */
    dbret = self->segments->open (self->segments, txn, tocname, "segments",
        DB_BTREE, DB_CREATE | DB_THREAD | DB_MULTIVERSION, 0);
    if (dbret != 0) {
        PyErr_Format (terane_Exc_Error, "Failed to open segments: %s",
            db_strerror (dbret));
        goto error;
    }

    /* commit new databases */
    dbret = txn->commit (txn, 0);
    if (dbret != 0) {
        PyErr_Format (terane_Exc_Error, "Failed to commit transaction: %s",
            db_strerror (dbret));
        goto error;
    }

    PyMem_Free (tocname);

    return 0;

/* if there is an error, then free any locally allocated memory and references */
error:
    if (txn != NULL)
        txn->abort (txn);
    if (tocname != NULL)
        PyMem_Free (tocname);
    if (self)
        _Index_dealloc ((terane_Index *) self);
    return -1;
}
Пример #19
0
nfsstat4 nfs_op_remove(struct nfs_cxn *cxn, const REMOVE4args *args,
		       struct list_head *writes, struct rpc_write **wr)
{
	nfsstat4 status = NFS4_OK;
	struct nfs_inode *dir_ino = NULL, *target_ino = NULL;
	struct nfs_buf target;
	change_info4 cinfo = { true, 0, 0 };
	DB_TXN *txn = NULL;
	DB_ENV *dbenv = srv.fsdb.env;
	int rc;
	nfsino_t de_inum;

	target.len = args->target.utf8string_len;
	target.val = args->target.utf8string_val;

	if (debugging)
		applog(LOG_INFO, "op REMOVE ('%.*s')",
		       target.len,
		       target.val);

	if (target.len > SRV_MAX_NAME) {
		status = NFS4ERR_NAMETOOLONG;
		goto out;
	}

	if (!valid_utf8string(&target)) {
		status = NFS4ERR_INVAL;
		goto out;
	}
	if (has_dots(&target)) {
		status = NFS4ERR_BADNAME;
		goto out;
	}

	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto out;
	}

	/* reference container directory */
	status = dir_curfh(txn, cxn, &dir_ino, DB_RMW);
	if (status != NFS4_OK)
		goto out_abort;

	/* lookup target name in directory */
	status = dir_lookup(txn, dir_ino, &target, 0, &de_inum);
	if (status != NFS4_OK)
		goto out_abort;

	/* reference target inode */
	target_ino = inode_getdec(txn, de_inum, DB_RMW);
	if (!target_ino) {
		status = NFS4ERR_NOENT;
		goto out_abort;
	}

	/* prevent root dir deletion */
	if (target_ino->inum == INO_ROOT) {
		status = NFS4ERR_INVAL;
		goto out_abort;
	}

	/* prevent removal of non-empty dirs */
	if ((target_ino->type == NF4DIR) && !dir_is_empty(txn, target_ino)) {
		status = NFS4ERR_NOTEMPTY;
		goto out_abort;
	}

	/* remove target inode from directory */
	rc = fsdb_dirent_del(&srv.fsdb, txn, dir_ino->inum, &target, 0);
	if (rc) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	/* record directory change info */
	cinfo.before = dir_ino->version;

	rc = inode_touch(txn, dir_ino);
	if (rc) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	cinfo.after = dir_ino->version;

	/* remove link, possibly deleting inode */
	rc = inode_unlink(txn, target_ino);
	if (rc) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		status = NFS4ERR_IO;
		goto out;
	}

out:
	WR32(status);
	if (status == NFS4_OK) {
		WR32(cinfo.atomic ? 1 : 0);	/* cinfo.atomic */
		WR64(cinfo.before);		/* cinfo.before */
		WR64(cinfo.after);		/* cinfo.after */
	}
	inode_free(dir_ino);
	inode_free(target_ino);
	return status;

out_abort:
	if (txn->abort(txn))
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	goto out;
}
Пример #20
0
bool has_access(const char *user, const char *bucket, const char *key,
		const char *perm_in)
{
	int rc;
	char perm[16];
	bool match = false;
	size_t alloc_len, key_len = 0;
	struct db_acl_key *acl_key;
	struct db_acl_ent *acl;
	DB_ENV *dbenv = tdbrep.tdb.env;
	DB_TXN *txn = NULL;
	DBT pkey, pval;
	DBC *cur = NULL;
	DB *acls = tdbrep.tdb.acls;

	if (user == NULL)
		user = DB_ACL_ANON;
	if (key == NULL)
		key = "";

	/* alloc ACL key on stack, sized to fit 'key' function arg */
	alloc_len = sizeof(struct db_acl_key) + 1;
	if (key) {
		key_len = strlen(key);
		alloc_len += key_len;
	}
	acl_key = alloca(alloc_len);

	/* fill in search key struct */
	memset(acl_key, 0, alloc_len);
	strncpy(acl_key->bucket, bucket, sizeof(acl_key->bucket));
	memcpy(acl_key->key, key, key_len);
	acl_key->key[key_len] = 0;

	snprintf(perm, sizeof(perm), "%s,", perm_in);

	/* open transaction, search cursor */
	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		return false;
	}

	rc = acls->cursor(acls, txn, &cur, 0);
	if (rc) {
		acls->err(acls, rc, "acls->cursor");
		goto err_out;
	}

	memset(&pkey, 0, sizeof(pkey));
	pkey.data = acl_key;
	pkey.size = alloc_len;

	memset(&pval, 0, sizeof(pval));
	pval.flags = DB_DBT_MALLOC;

	/* loop through matching records (if any) */
	rc = cur->get(cur, &pkey, &pval, DB_SET);
	while (rc == 0) {
		acl = pval.data;

		if (!strncmp(acl->grantee, user, sizeof(acl->grantee))) {
			match = (strstr(acl->perm, perm) != NULL);
			free(acl);
			break;
		}
		free(acl);

		memset(&pval, 0, sizeof(pval));
		pval.flags = DB_DBT_MALLOC;

		rc = cur->get(cur, &pkey, &pval, DB_NEXT_DUP);
	}

	if (rc && rc != DB_NOTFOUND)
		acls->err(acls, rc, "has_access iteration");

	/* close cursor, transaction */
	rc = cur->close(cur);
	if (rc)
		acls->err(acls, rc, "acls->cursor close");

	rc = txn->commit(txn, 0);
	if (rc)
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");

	return match;

err_out:
	rc = txn->abort(txn);
	if (rc)
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	return false;
}
Пример #21
0
nfsstat4 nfs_op_rename(struct nfs_cxn *cxn, const RENAME4args *args,
		       struct list_head *writes, struct rpc_write **wr)
{
	nfsstat4 status = NFS4_OK;
	struct nfs_inode *src_dir = NULL, *target_dir = NULL;
	struct nfs_inode *old_file = NULL, *new_file = NULL;
	struct nfs_buf oldname, newname;
	change_info4 src = { true, 0, 0 };
	change_info4 target = { true, 0, 0 };
	DB_TXN *txn = NULL;
	DB_ENV *dbenv = srv.fsdb.env;
	int rc;
	nfsino_t old_dirent, new_dirent;

	oldname.len = args->oldname.utf8string_len;
	oldname.val = args->oldname.utf8string_val;
	newname.len = args->newname.utf8string_len;
	newname.val = args->newname.utf8string_val;

	if (debugging)
		applog(LOG_INFO, "op RENAME (OLD:%.*s, NEW:%.*s)",
		       oldname.len,
		       oldname.val,
		       newname.len,
		       newname.val);

	/* validate text input */
	if ((!valid_utf8string(&oldname)) ||
	    (!valid_utf8string(&newname))) {
		status = NFS4ERR_INVAL;
		goto out;
	}
	if (has_dots(&oldname) || has_dots(&newname)) {
		status = NFS4ERR_BADNAME;
		goto out;
	}

	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto out;
	}

	/* reference source, target directories.
	 * NOTE: src_dir and target_dir may point to the same object
	 */
	src_dir = inode_fhdec(txn, cxn->save_fh, DB_RMW);
	if (fh_equal(cxn->save_fh, cxn->current_fh))
		target_dir = src_dir;
	else
		target_dir = inode_fhdec(txn, cxn->current_fh, DB_RMW);
	if (!src_dir || !target_dir) {
		status = NFS4ERR_NOFILEHANDLE;
		goto out_abort;
	}
	if ((src_dir->type != NF4DIR) || (target_dir->type != NF4DIR)) {
		status = NFS4ERR_NOTDIR;
		goto out_abort;
	}

	/* lookup source, target names */
	status = dir_lookup(txn, src_dir, &oldname, 0, &old_dirent);
	if (status != NFS4_OK)
		goto out_abort;

	old_file = inode_getdec(txn, old_dirent, 0);
	if (!old_file) {
		status = NFS4ERR_NOENT;
		goto out_abort;
	}

	status = dir_lookup(txn, target_dir, &newname, 0, &new_dirent);
	if (status != NFS4_OK && status != NFS4ERR_NOENT)
		goto out_abort;

	/* if target (newname) is present, attempt to remove */
	if (status == NFS4_OK) {
		bool ok_to_remove = false;

		/* read to-be-deleted inode */
		new_file = inode_getdec(txn, new_dirent, DB_RMW);
		if (!new_file) {
			status = NFS4ERR_NOENT;
			goto out_abort;
		}

		/* do oldname and newname refer to same file? */
		if (old_file->inum == new_file->inum) {
			src.after =
			src.before = src_dir->version;
			target.after =
			target.before = target_dir->version;
			goto out_abort;
		}

		if (old_file->type != NF4DIR && new_file->type != NF4DIR)
			ok_to_remove = true;
		else if (old_file->type == NF4DIR &&
			 new_file->type == NF4DIR &&
			 dir_is_empty(txn, new_file))
			ok_to_remove = true;

		if (!ok_to_remove) {
			status = NFS4ERR_EXIST;
			goto out_abort;
		}

		/* remove target inode from directory */
		rc = fsdb_dirent_del(&srv.fsdb, txn, target_dir->inum,
				     &newname, 0);
		if (rc == 0)
			rc = inode_unlink(txn, new_file);

		if (rc) {
			status = NFS4ERR_IO;
			goto out_abort;
		}
	} else
		status = NFS4_OK;

	new_dirent = old_dirent;

	/* delete entry from source directory; add to target directory */
	rc = fsdb_dirent_del(&srv.fsdb, txn, src_dir->inum, &oldname, 0);
	if (rc == 0)
		rc = fsdb_dirent_put(&srv.fsdb, txn, target_dir->inum,
				     &newname, 0, new_dirent);
	if (rc) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	/* if renamed file is a directory, ensure its 'parent' is updated */
	if (old_file->type == NF4DIR) {
		old_file->parent = target_dir->inum;
		if (inode_touch(txn, old_file)) {
			status = NFS4ERR_IO;
			goto out_abort;
		}
	}

	/* record directory change info */
	src.before = src_dir->version;
	target.before = target_dir->version;

	/* update last-modified stamps of directory inodes */
	rc = inode_touch(txn, src_dir);
	if (rc == 0 && src_dir != target_dir)
		rc = inode_touch(txn, target_dir);
	if (rc) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	/* close the transaction */
	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		status = NFS4ERR_IO;
		goto out;
	}

	src.after = src_dir->version;
	target.after = target_dir->version;

out:
	WR32(status);
	if (status == NFS4_OK) {
		WR32(src.atomic ? 1 : 0); /* src cinfo.atomic */
		WR64(src.before);	/* src cinfo.before */
		WR64(src.after);	/* src cinfo.after */
		WR32(target.atomic ? 1 : 0); /* target cinfo.atomic */
		WR64(target.before);	/* target cinfo.before */
		WR64(target.after);	/* target cinfo.after */
	}
	inode_free(src_dir);
	if (src_dir != target_dir)
		inode_free(target_dir);
	inode_free(old_file);
	inode_free(new_file);
	return status;

out_abort:
	if (txn->abort(txn))
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	goto out;
}
Пример #22
0
bool bucket_del(struct client *cli, const char *user, const char *bucket)
{
	char *hdr, timestr[64];
	enum errcode err = InternalError;
	int rc;
	struct db_bucket_ent ent;
	DB_ENV *dbenv = tdbrep.tdb.env;
	DB_TXN *txn = NULL;
	DB *buckets = tdbrep.tdb.buckets;
	DB *acls = tdbrep.tdb.acls;
	DB *objs = tdbrep.tdb.objs;
	DBC *cur = NULL;
	DBT key, val;
	char structbuf[sizeof(struct db_acl_key) + 32];
	struct db_acl_key *acl_key = (struct db_acl_key *) &structbuf;
	struct db_obj_key *obj_key = (struct db_obj_key *) &structbuf;

	if (!user)
		return cli_err(cli, AccessDenied);

	/* open transaction */
	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto err_none;
	}

	/* search for (bucket, *) in object database, to see if
	 * any objects associated with this bucket exist
	 */
	rc = objs->cursor(objs, txn, &cur, 0);
	if (rc) {
		objs->err(objs, rc, "objs->cursor");
		goto err_out;
	}

	memset(&structbuf, 0, sizeof(structbuf));
	strncpy(obj_key->bucket, bucket, sizeof(obj_key->bucket));
	obj_key->key[0] = 0;

	memset(&key, 0, sizeof(key));
	memset(&val, 0, sizeof(val));

	key.data = obj_key;
	key.size = sizeof(*obj_key) + strlen(obj_key->key) + 1;

	val.flags = DB_DBT_MALLOC;

	rc = cur->get(cur, &key, &val, DB_SET_RANGE);

	if (rc == 0) {
		struct db_obj_key *newkey = key.data;

		if (!strcmp(newkey->bucket, bucket)) {
			free(newkey);
			cur->close(cur);
			err = BucketNotEmpty;
			goto err_out;
		}

		free(newkey);
	} else if (rc != DB_NOTFOUND)
		objs->err(objs, rc, "bucket_del empty check");

	rc = cur->close(cur);
	if (rc) {
		objs->err(objs, rc, "objs->cursor_close");
		goto err_out;
	}

	memset(&key, 0, sizeof(key));
	key.data = (char *) bucket;
	key.size = strlen(bucket) + 1;

	memset(&val, 0, sizeof(val));
	val.data = &ent;
	val.ulen = sizeof(struct db_bucket_ent);
	val.flags = DB_DBT_USERMEM;

	/* verify the bucket exists */
	rc = buckets->get(buckets, txn, &key, &val, 0);
	if (rc) {
		if (rc == DB_NOTFOUND)
			err = NoSuchBucket;
		else
			buckets->err(buckets, rc, "buckets->get");
		goto err_out;
	}

	/* verify that it is the owner who wishes to delete bucket */
	if (strncmp(user, ent.owner, sizeof(ent.owner))) {
		err = AccessDenied;
		goto err_out;
	}

	/* delete bucket */
	rc = buckets->del(buckets, txn, &key, 0);
	if (rc) {
		buckets->err(buckets, rc, "bucket del");
		goto err_out;
	}

	/* delete bucket ACLs */
	memset(&structbuf, 0, sizeof(structbuf));
	strncpy(acl_key->bucket, bucket, sizeof(acl_key->bucket));
	acl_key->key[0] = 0;

	memset(&key, 0, sizeof(key));
	key.data = acl_key;
	key.size = sizeof(*acl_key) + strlen(acl_key->key) + 1;

	rc = acls->del(acls, txn, &key, 0);
	if (rc && rc != DB_NOTFOUND) {
		acls->err(acls, rc, "acl del");
		goto err_out;
	}

	/* commit */
	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		return cli_err(cli, InternalError);
	}

	if (asprintf(&hdr,
"HTTP/%d.%d 204 x\r\n"
"Content-Length: 0\r\n"
"Date: %s\r\n"
"Server: " PACKAGE_STRING "\r\n"
"\r\n",
		     cli->req.major,
		     cli->req.minor,
		     hutil_time2str(timestr, sizeof(timestr), time(NULL))) < 0)
		return cli_err(cli, InternalError);

	rc = atcp_writeq(&cli->wst, hdr, strlen(hdr), atcp_cb_free, hdr);
	if (rc) {
		free(hdr);
		return true;
	}

	return atcp_write_start(&cli->wst);

err_out:
	rc = txn->abort(txn);
	if (rc)
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
err_none:
	return cli_err(cli, err);
}
Пример #23
0
void CBDB_Env::JoinEnv(const string& db_home,
                       TEnvOpenFlags opt,
                       ETransactionDiscovery trans_test)
{
    int flag = DB_JOINENV;
    if (opt & eThreaded) {
        flag |= DB_THREAD;
    }

    Open(db_home, flag);


    switch (trans_test) {
    case eTestTransactions:
        {{
             // Check if we joined the transactional environment
             // Try to create a fake transaction to test the environment
             DB_TXN* txn = 0;
             int ret = m_Env->txn_begin(m_Env, 0, &txn, 0);

             if (ret == 0) {
                 m_Transactional = true;
                 ret = txn->abort(txn);
             }
         }}
        break;

    case eInspectTransactions:
        {{
             // Check if we joined the transactional environment
             Uint4 flags = 0;
             int ret = m_Env->get_open_flags(m_Env, &flags);
             BDB_CHECK(ret, "DB_ENV::get_open_flags");
             if (flags & DB_INIT_TXN) {
                 m_Transactional = true;
             } else {
                 m_Transactional = false;
             }
         }}
        break;
    case eAssumeTransactions:
        m_Transactional = true;
        break;
    case eAssumeNoTransactions:
        m_Transactional = false;
        break;
    default:
        _ASSERT(0);
    }

    // commented since it caused crash on windows trying to free
    // txn_statp structure. (Why it happened remains unknown)

/*
    DB_TXN_STAT *txn_statp = 0;
    int ret = m_Env->txn_stat(m_Env, &txn_statp, 0);
    if (ret == 0)
    {
        ::free(txn_statp);
        txn_statp = 0;

        // Try to create a fake transaction to test the environment
        DB_TXN* txn = 0;
        ret = m_Env->txn_begin(m_Env, 0, &txn, 0);

        if (ret == 0) {
            m_Transactional = true;
            ret = txn->abort(txn);
        }
    }
*/
}