diff options
author | jbj <devnull@localhost> | 2001-05-13 19:58:25 +0000 |
---|---|---|
committer | jbj <devnull@localhost> | 2001-05-13 19:58:25 +0000 |
commit | 2af040895b279eca8fb5a44240da7e42c8b4ac66 (patch) | |
tree | 1b74621cfd1f4531a39786c4b06a59bc0e92dbf7 /db/docs/ref/transapp | |
parent | 9b44f1b7168b70652f7fad2e0da6fdade4b965d7 (diff) | |
download | librpm-tizen-2af040895b279eca8fb5a44240da7e42c8b4ac66.tar.gz librpm-tizen-2af040895b279eca8fb5a44240da7e42c8b4ac66.tar.bz2 librpm-tizen-2af040895b279eca8fb5a44240da7e42c8b4ac66.zip |
Initial revision
CVS patchset: 4782
CVS date: 2001/05/13 19:58:25
Diffstat (limited to 'db/docs/ref/transapp')
-rw-r--r-- | db/docs/ref/transapp/nested.html | 65 | ||||
-rw-r--r-- | db/docs/ref/transapp/transapp.cs | 492 | ||||
-rw-r--r-- | db/docs/ref/transapp/tune.html | 92 | ||||
-rw-r--r-- | db/docs/ref/transapp/writetest.cs | 100 |
4 files changed, 749 insertions, 0 deletions
diff --git a/db/docs/ref/transapp/nested.html b/db/docs/ref/transapp/nested.html new file mode 100644 index 000000000..902f57ed3 --- /dev/null +++ b/db/docs/ref/transapp/nested.html @@ -0,0 +1,65 @@ +<!--Id: nested.so,v 10.22 2001/03/02 21:01:22 bostic Exp --> +<!--Copyright 1997-2001 by Sleepycat Software, Inc.--> +<!--All rights reserved.--> +<html> +<head> +<title>Berkeley DB Reference Guide: Nested transactions</title> +<meta name="description" content="Berkeley DB: An embedded database programmatic toolkit."> +<meta name="keywords" content="embedded,database,programmatic,toolkit,b+tree,btree,hash,hashing,transaction,transactions,locking,logging,access method,access methods,java,C,C++"> +</head> +<body bgcolor=white> + <a name="2"><!--meow--></a> +<table width="100%"><tr valign=top> +<td><h3><dl><dt>Berkeley DB Reference Guide:<dd>Berkeley DB Transactional Data Store Applications</dl></h3></td> +<td align=right><a href="../../ref/transapp/cursor.html"><img src="../../images/prev.gif" alt="Prev"></a><a href="../../reftoc.html"><img src="../../images/ref.gif" alt="Ref"></a><a href="../../ref/transapp/admin.html"><img src="../../images/next.gif" alt="Next"></a> +</td></tr></table> +<p> +<h1 align=center>Nested transactions</h1> +<p>Berkeley DB provides support for nested transactions. Nested transactions +allow an application to decompose a large or long-running transaction +into smaller units that may be independently aborted. +<p>Normally, when beginning a transaction, the application will pass a NULL +value for the parent argument to <a href="../../api_c/txn_begin.html">txn_begin</a>. If, however, the +parent argument is a DB_TXN handle, the newly created transaction +will be treated as a nested transaction within the parent. Transactions +may nest arbitrarily deeply. For the purposes of this discussion, +transactions created with a parent identifier will be called +<i>child transactions</i>. +<p>Once a transaction becomes a parent, as long as any of its child +transactions are unresolved (that is, they have neither committed nor +aborted), the parent may not issue any Berkeley DB calls except to begin more +child transactions, or to commit or abort. For example, it may not +issue any access method or cursor calls. After all of a parent's +children have committed or aborted, the parent may again request +operations on its own behalf. +<p>The semantics of nested transactions are as follows. When a child +transaction is begun, it inherits all the locks of its parent. This +means that the child will never block waiting on a lock held by its +parent. Further, locks held by two children of the same parent will +also conflict. To make this concrete, consider the following set of +transactions and lock acquisitions. +<p>Transaction T1 is the parent transaction. It acquires a write lock on +item A and then begins two child transactions: C1 and C2. C1 also +wishes to acquire a write lock on A; this succeeds. If C2 attempts to +acquire a write lock on A, it will block until C1 releases the lock, at +which point it will succeed. Now, let's say that C1 acquires a write +lock on B. If C2 now attempts to obtain a lock on B, it will block. +However, let's now assume that C1 commits. Its locks are +anti-inherited, which means they are given to T1, so T1 will now hold +a lock on B. At this point, C2 would be unblocked and would then +acquire a lock on B. +<p>Child transactions are entirely subservient to their parent transaction. +They may abort, undoing their operations regardless of the eventual fate +of the parent. However, even if a child transaction commits, if its +parent transaction is eventually aborted, the child's changes are undone +and the child's transaction is effectively aborted. Any child +transactions that are not yet resolved when the parent commits or aborts +are resolved based on the parent's resolution -- committing if the +parent commits and aborting if the parent aborts. Any child +transactions that are not yet resolved when the parent prepares are also +prepared. +<table width="100%"><tr><td><br></td><td align=right><a href="../../ref/transapp/cursor.html"><img src="../../images/prev.gif" alt="Prev"></a><a href="../../reftoc.html"><img src="../../images/ref.gif" alt="Ref"></a><a href="../../ref/transapp/admin.html"><img src="../../images/next.gif" alt="Next"></a> +</td></tr></table> +<p><font size=1><a href="http://www.sleepycat.com">Copyright Sleepycat Software</a></font> +</body> +</html> diff --git a/db/docs/ref/transapp/transapp.cs b/db/docs/ref/transapp/transapp.cs new file mode 100644 index 000000000..82e4fb42f --- /dev/null +++ b/db/docs/ref/transapp/transapp.cs @@ -0,0 +1,492 @@ +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> +#include <pthread.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <db.h> + +#define ENV_DIRECTORY "TXNAPP" + +void add_cat(DB_ENV *, DB *, char *, ...); +void add_color(DB_ENV *, DB *, char *, int); +void add_fruit(DB_ENV *, DB *, char *, char *); +void *checkpoint_thread(void *); +void log_archlist(DB_ENV *); +void *logfile_thread(void *); +void db_open(DB_ENV *, DB **, char *, int); +void env_dir_create(void); +void env_open(DB_ENV **); +void usage(void); + +int +main(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB *db_cats, *db_color, *db_fruit; + DB_ENV *dbenv; + pthread_t ptid; + int ch, ret; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + env_dir_create(); + env_open(&dbenv); + + /* Start a checkpoint thread. */ + if ((ret = pthread_create( + &ptid, NULL, checkpoint_thread, (void *)dbenv)) != 0) { + fprintf(stderr, + "txnapp: failed spawning checkpoint thread: %s\n", + strerror(ret)); + exit (1); + } + + /* Start a logfile removal thread. */ + if ((ret = pthread_create( + &ptid, NULL, logfile_thread, (void *)dbenv)) != 0) { + fprintf(stderr, + "txnapp: failed spawning log file removal thread: %s\n", + strerror(ret)); + exit (1); + } + + /* Open database: Key is fruit class; Data is specific type. */ + db_open(dbenv, &db_fruit, "fruit", 0); + + /* Open database: Key is a color; Data is an integer. */ + db_open(dbenv, &db_color, "color", 0); + + /* + * Open database: + * Key is a name; Data is: company name, address, cat breeds. + */ + db_open(dbenv, &db_cats, "cats", 1); + + add_fruit(dbenv, db_fruit, "apple", "yellow delicious"); + + add_color(dbenv, db_color, "blue", 0); + add_color(dbenv, db_color, "blue", 3); + + add_cat(dbenv, db_cats, + "Amy Adams", + "Sleepycat Software", + "394 E. Riding Dr., Carlisle, MA 01741, USA", + "abyssinian", + "bengal", + "chartreaux", + NULL); + + return (0); +} + +void +env_dir_create() +{ + struct stat sb; + + /* + * If the directory exists, we're done. We do not further check + * the type of the file, DB will fail appropriately if it's the + * wrong type. + */ + if (stat(ENV_DIRECTORY, &sb) == 0) + return; + + /* Create the directory, read/write/access owner only. */ + if (mkdir(ENV_DIRECTORY, S_IRWXU) != 0) { + fprintf(stderr, + "txnapp: mkdir: %s: %s\n", ENV_DIRECTORY, strerror(errno)); + exit (1); + } +} + +void +env_open(DB_ENV **dbenvp) +{ + DB_ENV *dbenv; + int ret; + + /* Create the environment handle. */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "txnapp: db_env_create: %s\n", db_strerror(ret)); + exit (1); + } + + /* Set up error handling. */ + dbenv->set_errpfx(dbenv, "txnapp"); + + /* Do deadlock detection internally. */ + if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT)) != 0) { + dbenv->err(dbenv, ret, "set_lk_detect: DB_LOCK_DEFAULT"); + exit (1); + } + + /* + * Open a transactional environment: + * create if it doesn't exist + * free-threaded handle + * run recovery + * read/write owner only + */ + if ((ret = dbenv->open(dbenv, ENV_DIRECTORY, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_THREAD, + S_IRUSR | S_IWUSR)) != 0) { + dbenv->err(dbenv, ret, "dbenv->open: %s", ENV_DIRECTORY); + exit (1); + } + + *dbenvp = dbenv; +} + +void * +checkpoint_thread(void *arg) +{ + DB_ENV *dbenv; + int ret; + + dbenv = arg; + dbenv->errx(dbenv, "Checkpoint thread: %lu", (u_long)pthread_self()); + + /* Checkpoint once a minute. */ + for (;; sleep(60)) + switch (ret = txn_checkpoint(dbenv, 0, 0, 0)) { + case 0: + case DB_INCOMPLETE: + break; + default: + dbenv->err(dbenv, ret, "checkpoint thread"); + exit (1); + } + + /* NOTREACHED */ +} + +void * +logfile_thread(void *arg) +{ + DB_ENV *dbenv; + int ret; + char **begin, **list; + + dbenv = arg; + dbenv->errx(dbenv, + "Log file removal thread: %lu", (u_long)pthread_self()); + + /* Check once every 5 minutes. */ + for (;; sleep(300)) { + /* Get the list of log files. */ + if ((ret = log_archive(dbenv, &list, DB_ARCH_ABS)) != 0) { + dbenv->err(dbenv, ret, "log_archive"); + exit (1); + } + + /* Remove the log files. */ + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + if ((ret = remove(*list)) != 0) { + dbenv->err(dbenv, + ret, "remove %s", *list); + exit (1); + } + free (begin); + } + } + /* NOTREACHED */ +} + +void +log_archlist(DB_ENV *dbenv) +{ + int ret; + char **begin, **list; + + /* Get the list of database files. */ + if ((ret = log_archive(dbenv, + &list, DB_ARCH_ABS | DB_ARCH_DATA)) != 0) { + dbenv->err(dbenv, ret, "log_archive: DB_ARCH_DATA"); + exit (1); + } + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + printf("database file: %s\n", *list); + free (begin); + } + + /* Get the list of log files. */ + if ((ret = log_archive(dbenv, + &list, DB_ARCH_ABS | DB_ARCH_LOG)) != 0) { + dbenv->err(dbenv, ret, "log_archive: DB_ARCH_LOG"); + exit (1); + } + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + printf("log file: %s\n", *list); + free (begin); + } +} + +void +db_open(DB_ENV *dbenv, DB **dbp, char *name, int dups) +{ + DB *db; + int ret; + + /* Create the database handle. */ + if ((ret = db_create(&db, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + exit (1); + } + + /* Optionally, turn on duplicate data items. */ + if (dups && (ret = db->set_flags(db, DB_DUP)) != 0) { + dbenv->err(dbenv, ret, "db->set_flags: DB_DUP"); + exit (1); + } + + /* + * Open a database in the environment: + * create if it doesn't exist + * free-threaded handle + * read/write owner only + */ + if ((ret = db->open(db, name, NULL, + DB_BTREE, DB_CREATE | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) { + dbenv->err(dbenv, ret, "db->open: %s", name); + exit (1); + } + + *dbp = db; +} + +void +add_fruit(DB_ENV *dbenv, DB *db, char *fruit, char *name) +{ + DBT key, data; + DB_TXN *tid; + int ret; + + /* Initialization. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = fruit; + key.size = strlen(fruit); + data.data = name; + data.size = strlen(name); + + for (;;) { + /* Begin the transaction. */ + if ((ret = txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_begin"); + exit (1); + } + + /* Store the value. */ + switch (ret = db->put(db, tid, &key, &data, 0)) { + case 0: + /* Success: commit the change. */ + if ((ret = txn_commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_commit"); + exit (1); + } + return; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + break; + default: + /* Error: run recovery. */ + dbenv->err(dbenv, ret, "dbc->put: %s/%s", fruit, name); + exit (1); + } + } +} + +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 = txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "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 = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "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 = txn_commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_commit"); + exit (1); + } + return; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + break; + default: + /* Error: run recovery. */ + dbenv->err( + dbenv, ret, "dbc->put: %s/%d", color, increment); + exit (1); + } + } +} + +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 = txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "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 = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "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 = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "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 = txn_commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_commit"); + exit (1); + } +} + +void +usage() +{ + (void)fprintf(stderr, "usage: txnapp\n"); + exit(1); +} diff --git a/db/docs/ref/transapp/tune.html b/db/docs/ref/transapp/tune.html new file mode 100644 index 000000000..a8bf1b66c --- /dev/null +++ b/db/docs/ref/transapp/tune.html @@ -0,0 +1,92 @@ +<!--Id: tune.so,v 11.8 2001/04/04 22:32:29 bostic Exp --> +<!--Copyright 1997-2001 by Sleepycat Software, Inc.--> +<!--All rights reserved.--> +<html> +<head> +<title>Berkeley DB Reference Guide: Transaction tuning</title> +<meta name="description" content="Berkeley DB: An embedded database programmatic toolkit."> +<meta name="keywords" content="embedded,database,programmatic,toolkit,b+tree,btree,hash,hashing,transaction,transactions,locking,logging,access method,access methods,java,C,C++"> +</head> +<body bgcolor=white> + <a name="2"><!--meow--></a> <a name="3"><!--meow--></a> +<table width="100%"><tr valign=top> +<td><h3><dl><dt>Berkeley DB Reference Guide:<dd>Berkeley DB Transactional Data Store Applications</dl></h3></td> +<td align=right><a href="../../ref/transapp/reclimit.html"><img src="../../images/prev.gif" alt="Prev"></a><a href="../../reftoc.html"><img src="../../images/ref.gif" alt="Ref"></a><a href="../../ref/transapp/throughput.html"><img src="../../images/next.gif" alt="Next"></a> +</td></tr></table> +<p> +<h1 align=center>Transaction tuning</h1> +<p>There are a few different issues to consider when tuning the performance +of Berkeley DB transactional applications. First, you should review +<a href="../../ref/am_misc/tune.html">Access method tuning</a>, as the +tuning issues for access method applications are applicable to +transactional applications as well. The following are additional tuning +issues for Berkeley DB transactional applications: +<p><dl compact> +<p><dt>access method<dd>Highly concurrent applications should use the Queue access method, where +possible, as it provides finer-granularity of locking than the other +access methods. Otherwise, applications usually see better concurrency +when using the Btree access method than when using either the Hash or +Recno access methods. +<p><dt>record numbers<dd>Using record numbers outside of the Queue access method will often slow +down concurrent applications as they limit the degree of concurrency +available in the database. +Using the Recno access method, or the Btree access +method with retrieval by record number configured can slow applications +down. +<p><dt>Btree database size<dd>When using the Btree access method, applications supporting concurrent +access may see excessive numbers of deadlocks in small databases. There +are two different approaches to resolving this problem. First, as the +Btree access method uses page-level locking, decreasing the database +page size can result in fewer lock conflicts. Second, in the case of +databases that are cyclically growing and shrinking, turning off reverse +splits can leave the database with enough pages that there will be fewer +lock conflicts. +<p><dt>transactionally protected read operations<dd>Most applications do not need repeatable reads. Performing all read +operations outside of transactions can often significantly increase +application throughput. In addition, limiting the lifetime of +non-transactional cursors will reduce the length of times locks are +held, thereby improving concurrency. +<p><dt><a href="../../api_c/db_open.html#DB_DIRTY_READ">DB_DIRTY_READ</a><dd>Consider using the <a href="../../api_c/db_open.html#DB_DIRTY_READ">DB_DIRTY_READ</a> flag for transactions, cursors +or individual read operations. This flag allows read operations to +potentially return data which has been modified but not yet committed, +and can significantly increase application throughput in applications +that do not require data be guaranteed to be permanent in the database. +<p><dt><a href="../../api_c/dbc_get.html#DB_RMW">DB_RMW</a><dd>Consider using the <a href="../../api_c/dbc_get.html#DB_RMW">DB_RMW</a> flag to immediate acquire write locks +when reading data items that will subsequently be modified. Although +this flag may increase contention (because write locks are held longer +than they would otherwise be), it may decrease the number of deadlocks +that occur. +<p><dt><a href="../../api_c/env_open.html#DB_TXN_NOSYNC">DB_TXN_NOSYNC</a><dd>By default, transactional commit in Berkeley DB implies durability, that is, +all committed operations will be present in the database after +recovery from any application or system failure. For applications not +requiring that level of certainty, specifying the <a href="../../api_c/env_open.html#DB_TXN_NOSYNC">DB_TXN_NOSYNC</a> +flag will often provide a significant performance improvement. In this +case, the database will still be fully recoverable, but some number of +committed transactions might be lost after system failure. +<p><dt>large key/data items<dd>Transactional protections in Berkeley DB are guaranteed by before and after +physical image logging. This means applications modifying large +key/data items also write large log records, and, in the case of the +default transaction commit, threads of control must wait until those +log records have been flushed to disk. Applications supporting +concurrent access should try and keep key/data items small wherever +possible. +<p><dt>log buffer size<dd>Berkeley DB internally maintains a buffer of log writes. The buffer is +written to disk at transaction commit, by default, or, whenever it +is filled. If it is consistently being filled before transaction +commit, it will be written multiple times per transaction, costing +application performance. In these cases, increasing the size of the +log buffer can increase application throughput. +<p><dt>trickle write<dd>In some applications, the cache is sufficiently active and dirty that +readers frequently need to write a dirty page in order to have space in +which to read a new page from the backing database file. You can use +the <a href="../../utility/db_stat.html">db_stat</a> utility (or the statistics returned by the +<a href="../../api_c/memp_stat.html">memp_stat</a> function) to see how often this is happening in your +application's cache. In this case, using a separate thread of control +and the <a href="../../api_c/memp_trickle.html">memp_trickle</a> interface to trickle-write pages can often +increase the overall throughput of the application. +</dl> +<table width="100%"><tr><td><br></td><td align=right><a href="../../ref/transapp/reclimit.html"><img src="../../images/prev.gif" alt="Prev"></a><a href="../../reftoc.html"><img src="../../images/ref.gif" alt="Ref"></a><a href="../../ref/transapp/throughput.html"><img src="../../images/next.gif" alt="Next"></a> +</td></tr></table> +<p><font size=1><a href="http://www.sleepycat.com">Copyright Sleepycat Software</a></font> +</body> +</html> diff --git a/db/docs/ref/transapp/writetest.cs b/db/docs/ref/transapp/writetest.cs new file mode 100644 index 000000000..bde092cb6 --- /dev/null +++ b/db/docs/ref/transapp/writetest.cs @@ -0,0 +1,100 @@ +/* + * writetest -- + * + * Id: writetest.cs,v 10.3 1999/11/19 17:21:06 bostic Exp + */ +#include <sys/types.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct timeval start_time, end_time; + long usecs; + int bytes, ch, cnt, fd, ops; + char *fname, buf[100 * 1024]; + + bytes = 256; + fname = "testfile"; + ops = 1000; + while ((ch = getopt(argc, argv, "b:f:o:")) != EOF) + switch (ch) { + case 'b': + if ((bytes = atoi(optarg)) > sizeof(buf)) { + fprintf(stderr, + "max -b option %d\n", sizeof(buf)); + exit (1); + } + break; + case 'f': + fname = optarg; + break; + case 'o': + if ((ops = atoi(optarg)) <= 0) { + fprintf(stderr, "illegal -o option value\n"); + exit (1); + } + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + (void)unlink(fname); + if ((fd = open(fname, O_RDWR | O_CREAT, 0666)) == -1) { + perror(fname); + exit (1); + } + + memset(buf, 0, bytes); + + printf("running: %d ops\n", ops); + + (void)gettimeofday(&start_time, NULL); + for (cnt = 0; cnt < ops; ++cnt) { + if (write(fd, buf, bytes) != bytes) { + fprintf(stderr, "write: %s\n", strerror(errno)); + exit (1); + } + if (lseek(fd, (off_t)0, SEEK_SET) == -1) { + fprintf(stderr, "lseek: %s\n", strerror(errno)); + exit (1); + } + if (fsync(fd) != 0) { + fprintf(stderr, "fsync: %s\n", strerror(errno)); + exit (1); + } + } + (void)gettimeofday(&end_time, NULL); + + usecs = (end_time.tv_sec - start_time.tv_sec) * 1000000 + + end_time.tv_usec - start_time.tv_usec; + printf("Elapsed time: %ld.%06ld seconds\n", + usecs / 1000000, usecs % 1000000); + printf("%d ops: %7.2f ops per second\n", + ops, (float)1000000 * ops/usecs); + + (void)unlink(fname); + exit (0); +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: testfile [-b bytes] [-f file] [-o ops]\n"); + exit(1); +} |