Import BSDDB 4.7.25 (as of svn r89086)
This commit is contained in:
262
tcl/docs/db.html
Normal file
262
tcl/docs/db.html
Normal file
@@ -0,0 +1,262 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.08 [en] (X11; I; FreeBSD 3.3-RELEASE i386) [Netscape]">
|
||||
</HEAD>
|
||||
<BODY>
|
||||
|
||||
<H2>
|
||||
<A NAME="Database Commands"></A>Database Commands</H2>
|
||||
The database commands provide a fairly straightforward mapping to the
|
||||
DB method functions.
|
||||
|
||||
<P>
|
||||
<B>> berkdb open</B>
|
||||
<dl>
|
||||
|
||||
<dt><B>[-btcompare <I>proc</I>]</B><dd>
|
||||
Sets the Btree comparison function to the Tcl procedure named
|
||||
<I>proc</I> using the
|
||||
<A HREF="../../docs/api_c/db_set_bt_compare.html">DB->set_bt_compare</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-btree|-hash|-recno|-queue|-unknown]</B><dd>
|
||||
</td><td>
|
||||
Select the database type:<br>
|
||||
DB_BTREE, DB_HASH, DB_RECNO, DB_QUEUE or DB_UNKNOWN.
|
||||
|
||||
|
||||
<dt><B>[-cachesize {<I>gbytes bytes ncaches</I>}]</B><dd>
|
||||
Sets the size of the database cache to the size specified by
|
||||
<I>gbytes</I> and <I>bytes</I>, broken up into <I>ncaches</I> number of
|
||||
caches using the
|
||||
<A HREF="../../docs/api_c/db_set_cachesize.html">DB->set_cachesize</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-create]</B><dd>
|
||||
Selects the DB_CREATE flag to create underlying files.
|
||||
|
||||
<dt><B>[-delim <I>delim</I>]</B><dd>
|
||||
Sets the delimiting byte for variable length records to <I>delim</I>
|
||||
using the
|
||||
<A HREF="../../docs/api_c/db_set_re_delim.html">DB->set_re_delim</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-dup]</B><dd>
|
||||
Selects the DB_DUP flag to permit duplicates in the database.
|
||||
|
||||
<dt><B>[-dupcompare <I>proc</I>]</B><dd>
|
||||
Sets the duplicate data comparison function to the Tcl procedure named
|
||||
<I>proc</I> using the
|
||||
<A HREF="../../docs/api_c/db_set_dup_compare.html">DB->set_dup_compare</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-dupsort]</B><dd>
|
||||
Selects the DB_DUPSORT flag to support sorted duplicates.
|
||||
|
||||
<dt><B>[-env <I>env</I>]</B><dd>
|
||||
The database environment.
|
||||
|
||||
<dt><B>[-errfile <I>filename</I>]</B><dd>
|
||||
Specifies the error file to use for this environment to <I>filename</I>
|
||||
by calling
|
||||
<A HREF="../../docs/api_c/db_set_errfile.html">DB->set_errfile</A>.
|
||||
If the file already exists then we will append to the end of the file.
|
||||
|
||||
<dt><B>[-excl]</B><dd>
|
||||
Selects the DB_EXCL flag to exclusively create underlying files.
|
||||
|
||||
<dt><B>[-extent <I>size</I>]</B><dd>
|
||||
Sets the size of a Queue database extent to the given <I>size</I> using
|
||||
the
|
||||
<A HREF="../../docs/api_c/db_set_q_extentsize.html">DB->set_q_extentsize</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-ffactor <I>density</I>]</B><dd>
|
||||
Sets the hash table key density to the given <I>density</I> using the
|
||||
<A HREF="../../docs/api_c/db_set_h_ffactor.html">DB->set_h_ffactor</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-hashproc <I>proc</I>]</B><dd>
|
||||
Sets a user-defined hash function to the Tcl procedure named <I>proc</I>
|
||||
using the
|
||||
<A HREF="../../docs/api_c/db_set_h_hash.html">DB->set_h_hash</A> method.
|
||||
|
||||
<dt><B>[-len <I>len</I>]</B><dd>
|
||||
Sets the length of fixed-length records to <I>len</I> using the
|
||||
<A HREF="../../docs/api_c/db_set_re_len.html">DB->set_re_len</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-lorder <I>order</I>]</B><dd>
|
||||
Sets the byte order for integers stored in the database meta-data to
|
||||
the given <I>order</I> using the
|
||||
<A HREF="../../docs/api_c/db_set_lorder.html">DB->set_lorder</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-minkey <I>minkey</I>]</B><dd>
|
||||
Sets the minimum number of keys per Btree page to <I>minkey</I> using
|
||||
the
|
||||
<A HREF="../../docs/api_c/db_set_bt_minkey.html">DB->set_bt_minkey</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-mode <I>mode</I>]</B><dd>
|
||||
Specifies the mode for created files.
|
||||
|
||||
<dt><B>[-nelem <I>size</I>]</B><dd>
|
||||
Sets the hash table size estimate to the given <I>size</I> using the
|
||||
<A HREF="../../docs/api_c/db_set_h_nelem.html">DB->set_h_nelem</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-nommap]</B><dd>
|
||||
Selects the DB_NOMMAP flag to forbid mmaping of files.
|
||||
|
||||
<dt><B>[-pad <I>pad</I>]</B><dd>
|
||||
Sets the pad character used for fixed length records to <I>pad</I> using
|
||||
the
|
||||
<A HREF="../../docs/db_set_re_pad.html">DB->set_re_pad</A> method.
|
||||
|
||||
<dt><B>[-pagesize <I>pagesize</I>]</B><dd>
|
||||
Sets the size of the database page to <I>pagesize</I> using the
|
||||
<A HREF="../../docs/api_c/db_set_pagesize.html">DB->set_pagesize</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-rdonly]</B><dd>
|
||||
Selects the DB_RDONLY flag for opening in read-only mode.
|
||||
|
||||
<dt><B>[-recnum]</B><dd>
|
||||
Selects the DB_RECNUM flag to support record numbers in Btrees.
|
||||
|
||||
<dt><B>[-renumber]</B><dd>
|
||||
Selects the DB_RENUMBER flag to support mutable record numbers.
|
||||
|
||||
<dt><B>[-revsplitoff]</B><dd>
|
||||
Selects the DB_REVSPLITOFF flag to suppress reverse splitting of pages
|
||||
on deletion.
|
||||
|
||||
<dt><B>[-snapshot]</B><dd>
|
||||
Selects the DB_SNAPSHOT flag to support database snapshots.
|
||||
|
||||
<dt><B>[-source <I>file</I>]</B><dd>
|
||||
Sets the backing source file name to <I>file</I> using the
|
||||
<A HREF="../../docs/api_c/db_set_re_source.html">DB->set_re_source</A>
|
||||
method.
|
||||
|
||||
<dt><B>[-truncate]</B><dd>
|
||||
Selects the DB_TRUNCATE flag to truncate the database.
|
||||
|
||||
<dt><B>[--]</B><dd>
|
||||
Terminate the list of options and use remaining arguments as the file
|
||||
or subdb names (thus allowing the use of filenames beginning with a dash
|
||||
'-').
|
||||
|
||||
<dt><B>[<I>filename </I>[<I>subdbname</I>]]</B><dd>
|
||||
The names of the database and sub-database.
|
||||
</dl>
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<B>> berkdb upgrade [-dupsort] [-env <I>env</I>] [--] [<I>filename</I>]</B>
|
||||
<P>This command will invoke the <A HREF="../../docs/api_c/db_upgrade.html">DB->upgrade</A>
|
||||
function. If the command is given the <B>-env</B> option, then we
|
||||
will accordingly upgrade the database filename within the context of that
|
||||
environment. The <B>-dupsort</B> option selects the DB_DUPSORT flag for
|
||||
upgrading. The use of --<B> </B>terminates the list of options, thus allowing
|
||||
filenames beginning with a dash.
|
||||
<P>
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<B>> berkdb verify [-env <I>env</I>] [--] [<I>filename</I>]</B>
|
||||
<P>This command will invoke the <A HREF="../../docs/api_c/db_verify.html">DB->verify</A>
|
||||
function. If the command is given the <B>-env</B> option, then we
|
||||
will accordingly verify the database filename within the context of that
|
||||
environment. The use of --<B> </B>terminates the list of options,
|
||||
thus allowing filenames beginning with a dash.
|
||||
<P>
|
||||
|
||||
<HR WIDTH="100%"><B>> <I>db</I> del</B>
|
||||
<P>There are no undocumented options.
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<B>> <I>db</I> join [-nosort] <I>db0.c0 db1.c0</I> ...</B>
|
||||
<P>This command will invoke the <A HREF="../../docs/api_c/db_join.html">db_join</A>
|
||||
function. After it successfully joins a database, we bind it to a
|
||||
new Tcl command of the form <B><I>dbN.cX, </I></B>where X is an integer
|
||||
starting at 0 (e.g. <B>db2.c0, db3.c0, </B>etc). We use the <I>Tcl_CreateObjCommand() </I>
|
||||
to create the top level database function. It is through this cursor
|
||||
handle that the user can access the joined data items.
|
||||
<P>The options are:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>-nosort -</B> This flag causes DB not to sort the cursors based on the
|
||||
number of data items they reference. It results in the DB_JOIN_NOSORT
|
||||
flag being set.</LI>
|
||||
</UL>
|
||||
|
||||
<P>
|
||||
This command will invoke the
|
||||
<A HREF="../../docs/api_c/db_create.html">db_create</A> function. If
|
||||
the command is given the <B>-env</B> option, then we will accordingly
|
||||
creating the database within the context of that environment. After it
|
||||
successfully gets a handle to a database, we bind it to a new Tcl
|
||||
command of the form <B><I>dbX, </I></B>where X is an integer starting
|
||||
at 0 (e.g. <B>db0, db1, </B>etc).
|
||||
|
||||
<p>
|
||||
We use the <I>Tcl_CreateObjCommand()</I> to create the top level
|
||||
database function. It is through this handle that the user can access
|
||||
all of the commands described in the <A HREF="#Database Commands">
|
||||
Database Commands</A> section. Internally, the database handle
|
||||
is sent as the <I>ClientData</I> portion of the new command set so that
|
||||
all future database calls access the appropriate handle.
|
||||
|
||||
<P>
|
||||
After parsing all of the optional arguments affecting the setup of the
|
||||
database and making the appropriate calls to DB to manipulate those
|
||||
values, we open the database for the user. It translates to the
|
||||
<A HREF="../../docs/api_c/db_open.html">DB->open</A> method call after
|
||||
parsing all of the various optional arguments. We automatically set the
|
||||
DB_THREAD flag. The arguments are:
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<B>> <I>db</I> get_join [-nosort] {db key} {db key} ...</B>
|
||||
<P>This command performs a join operation on the keys specified and returns
|
||||
a list of the joined {key data} pairs.
|
||||
<P>The options are:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>-nosort</B> This flag causes DB not to sort the cursors based on the
|
||||
number of data items they reference. It results in the DB_JOIN_NOSORT
|
||||
flag being set.</LI>
|
||||
</UL>
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<B>> <I>db</I> keyrange [-txn <I>id</I>] key</B>
|
||||
<P>This command returns the range for the given <B>key</B>. It returns
|
||||
a list of 3 double elements of the form {<B><I>less equal greater</I></B>}
|
||||
where <B><I>less</I></B> is the percentage of keys less than the given
|
||||
key, <B><I>equal</I></B> is the percentage equal to the given key and <B><I>greater</I></B>
|
||||
is the percentage greater than the given key. If the -txn option
|
||||
is specified it performs this operation under transaction protection.
|
||||
|
||||
<HR WIDTH="100%"><B>> <I>db</I> put</B>
|
||||
<P>The <B>undocumented</B> options are:
|
||||
<dl>
|
||||
<dt><B>-nodupdata</B><dd>
|
||||
This flag causes DB not to insert the key/data pair if it already
|
||||
exists, that is, both the key and data items are already in the
|
||||
database. The -nodupdata flag may only be specified if the underlying
|
||||
database has been configured to support sorted duplicates.
|
||||
</dl>
|
||||
|
||||
<HR WIDTH="100%"><B>> <I>dbc</I> put</B>
|
||||
<P>The <B>undocumented</B> options are:
|
||||
<dl>
|
||||
<dt><B>-nodupdata</B><dd>
|
||||
This flag causes DB not to insert the key/data pair if it already
|
||||
exists, that is, both the key and data items are already in the
|
||||
database. The -nodupdata flag may only be specified if the underlying
|
||||
database has been configured to support sorted duplicates.
|
||||
</dl>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
344
tcl/docs/env.html
Normal file
344
tcl/docs/env.html
Normal file
@@ -0,0 +1,344 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.75 [en] (X11; U; Linux 2.2.16-22 i686) [Netscape]">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>
|
||||
Environment Commands</h2>
|
||||
Environments provide a structure for creating a consistent environment
|
||||
for processes using one or more of the features of Berkeley DB. Unlike
|
||||
some of the database commands, the environment commands are very low level.
|
||||
<br>
|
||||
<hr WIDTH="100%">
|
||||
<p>The user may create and open a new DB environment by invoking:
|
||||
<p><b>> berkdb env</b>
|
||||
<br><b> [-cdb] [-cdb_alldb] [-lock] [-log] [-txn [nosync]]</b>
|
||||
<br><b> [-create] [-home<i> directory</i>] [-mode <i>mode</i>]</b>
|
||||
<br><b> [-data_dir <i>directory</i>] [-log_dir <i>directory</i>]
|
||||
[-tmp_dir <i>directory</i>]</b>
|
||||
<br><b> [-nommap] [-private] [-recover] [-recover_fatal]
|
||||
[-system_mem] [-errfile <i>filename</i>]</b>
|
||||
<br><b> [-use_environ] [-use_environ_root] [-verbose
|
||||
{<i>which </i>on|off}]</b>
|
||||
<br><b> [-region_init]</b>
|
||||
<br><b> [-cachesize {<i>gbytes bytes ncaches</i>}]</b>
|
||||
<br><b> [-mmapsize<i> size</i>]</b>
|
||||
<br><b> [-log_max <i>max</i>]</b>
|
||||
<br><b> [-log_buffer <i>size</i>]</b>
|
||||
<br><b> [-lock_conflict {<i>nmodes </i>{<i>matrix</i>}}]</b>
|
||||
<br><b> [-lock_detect default|oldest|random|youngest]</b>
|
||||
<br><b> [-lock_max <i>max</i>]</b>
|
||||
<br><b> [-lock_max_locks <i>max</i>]</b>
|
||||
<br><b> [-lock_max_lockers <i>max</i>]</b>
|
||||
<br><b> [-lock_max_objects <i>max</i>]</b>
|
||||
<br><b> [-lock_timeout <i>timeout</i>]</b>
|
||||
<br><b> [-overwrite]</b>
|
||||
<br><b> [-txn_max <i>max</i>]</b>
|
||||
<br><b> [-txn_timeout <i>timeout</i>]</b>
|
||||
<br><b> [-client_timeout <i>seconds</i>]</b>
|
||||
<br><b> [-server_timeout <i>seconds</i>]</b>
|
||||
<br><b> [-server <i>hostname</i>]</b>
|
||||
<br><b> [-rep_master] [-rep_client]</b>
|
||||
<br><b> [-rep_transport <i>{ machineid sendproc }</i>]</b>
|
||||
<br>
|
||||
<p>This command opens up an environment. We automatically set
|
||||
the DB_THREAD and the DB_INIT_MPOOL flags. The arguments are:
|
||||
<ul>
|
||||
<li>
|
||||
<b>-cdb</b> selects the DB_INIT_CDB flag for Concurrent Data Store</li>
|
||||
|
||||
<li>
|
||||
<b>-cdb_alldb</b> selects the DB_CDB_ALLDB flag for Concurrent Data Store</li>
|
||||
|
||||
<li>
|
||||
<b>-lock</b> selects the DB_INIT_LOCK flag for the locking subsystem</li>
|
||||
|
||||
<li>
|
||||
<b>-log</b> selects the DB_INIT_LOG flag for the logging subsystem</li>
|
||||
|
||||
<li>
|
||||
<b>-txn</b> selects the DB_INIT_TXN, DB_INIT_LOCK and DB_INIT_LOG flags
|
||||
for the transaction subsystem. If <b>nosync</b> is specified, then
|
||||
it will also select DB_TXN_NOSYNC to indicate no flushes of log on commits</li>
|
||||
|
||||
<li>
|
||||
<b>-create </b>selects the DB_CREATE flag to create underlying files</li>
|
||||
|
||||
<li>
|
||||
<b>-home <i>directory </i></b>selects the home directory of the environment</li>
|
||||
|
||||
<li>
|
||||
<b>-data_dir <i>directory </i></b>selects the data file directory of the
|
||||
environment by calling <a href="../../docs/api_c/env_set_data_dir.html">DBENV->set_data_dir</a>.</li>
|
||||
|
||||
<li>
|
||||
<b>-log_dir <i>directory </i></b>selects the log file directory of the
|
||||
environment by calling <a href="../../docs/api_c/env_set_lg_dir.html">DBENV->set_lg_dir</a>.</li>
|
||||
|
||||
<li>
|
||||
<b>-tmp_dir <i>directory </i></b>selects the temporary file directory of
|
||||
the environment by calling <a href="../../docs/api_c/env_set_tmp_dir.so">DBENV->set_tmp_dir</a>.</li>
|
||||
|
||||
<li>
|
||||
<b>-mode <i>mode </i></b>sets the permissions of created files to <b><i>mode</i></b></li>
|
||||
|
||||
<li>
|
||||
<b>-nommap</b> selects the DB_NOMMAP flag to disallow using mmap'ed files</li>
|
||||
|
||||
<li>
|
||||
<b>-private</b> selects the DB_PRIVATE flag for a private environment</li>
|
||||
|
||||
<li>
|
||||
<b>-recover</b> selects the DB_RECOVER flag for recovery</li>
|
||||
|
||||
<li>
|
||||
<b>-recover_fatal</b> selects the DB_RECOVER_FATAL flag for catastrophic
|
||||
recovery</li>
|
||||
|
||||
<li>
|
||||
<b>-system_mem</b> selects the DB_SYSTEM_MEM flag to use system memory</li>
|
||||
|
||||
<li>
|
||||
<b>-errfile </b>specifies the error file to use for this environment to
|
||||
<b><i>filename</i></b>
|
||||
by calling <a href="../../docs/api_c/env_set_errfile.html">DBENV->set_errfile</a><b><i>.
|
||||
</i></b>If
|
||||
the file already exists then we will append to the end of the file</li>
|
||||
|
||||
<li>
|
||||
<b>-use_environ</b> selects the DB_USE_ENVIRON flag to affect file naming</li>
|
||||
|
||||
<li>
|
||||
<b>-use_environ_root</b> selects the DB_USE_ENVIRON_ROOT flag to have the
|
||||
root environment affect file naming</li>
|
||||
|
||||
<li>
|
||||
<b>-verbose</b> produces verbose error output for the given which subsystem,
|
||||
using the <a href="../../docs/api_c/dbenv_set_verbose.html">DBENV->set_verbose</a>
|
||||
method. See the description of <a href="#> <env> verbose which on|off">verbose</a>
|
||||
below for valid <b><i>which </i></b>values</li>
|
||||
|
||||
<li>
|
||||
<b>-region_init </b>specifies that the user wants to page fault the region
|
||||
in on startup using the <a href="../../docs/api_c/env_set_region_init.html">DBENV->set_region_init</a>
|
||||
method call</li>
|
||||
|
||||
<li>
|
||||
<b>-cachesize </b>sets the size of the database cache to the size
|
||||
specified by <b><i>gbytes </i></b>and <b><i>bytes, </i></b>broken up into
|
||||
<b><i>ncaches</i></b>
|
||||
number of caches using the <a href="../../docs/api_c/env_set_cachesize.html">DBENV->set_cachesize</a>
|
||||
method</li>
|
||||
|
||||
<li>
|
||||
<b>-mmapsize </b>sets the size of the database page to <b><i>size </i></b>using
|
||||
the <a href="../../docs/api_c/env_set_mp_mmapsize.html">DBENV->set_mp_mmapsize</a>
|
||||
method</li>
|
||||
|
||||
<li>
|
||||
<b>-log_max </b>sets the maximum size of the log file to <b><i>max</i></b>
|
||||
using the <a href="../../docs/api_c/env_set_lg_max.html">DBENV->set_lg_max</a>
|
||||
call</li>
|
||||
|
||||
<li>
|
||||
<b>-log_regionmax </b>sets the size of the log region to <b><i>max</i></b>
|
||||
using the <a href="../../docs/api_c/env_set_lg_regionmax.html">DBENV->set_lg_regionmax</a>
|
||||
call</li>
|
||||
|
||||
<li>
|
||||
<b>-log_buffer </b>sets the size of the log file in bytes to <b><i>size</i></b>
|
||||
using the <a href="../../docs/api_c/env_set_lg_bsize.html">DBENV->set_lg_bsize</a>
|
||||
call</li>
|
||||
|
||||
<li>
|
||||
<b>-lock_conflict </b>sets the number of lock modes to <b><i>nmodes</i></b>
|
||||
and sets the locking policy for those modes to the <b><i>conflict_matrix</i></b>
|
||||
given using the <a href="../../docs/api_c/env_set_lk_conflict.html">DBENV->set_lk_conflict</a>
|
||||
method call</li>
|
||||
|
||||
<li>
|
||||
<b>-lock_detect </b>sets the deadlock detection policy to the given policy
|
||||
using the <a href="../../docs/env_set_lk_detect.html">DBENV->set_lk_detect</a>
|
||||
method call. The policy choices are:</li>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>default</b> selects the DB_LOCK_DEFAULT policy for default detection</li>
|
||||
|
||||
<li>
|
||||
<b>oldest </b>selects DB_LOCK_OLDEST to abort the oldest locker on a deadlock</li>
|
||||
|
||||
<li>
|
||||
<b>random</b> selects DB_LOCK_RANDOM to abort a random locker on a deadlock</li>
|
||||
|
||||
<li>
|
||||
<b>youngest</b> selects DB_LOCK_YOUNGEST to abort the youngest locker on
|
||||
a deadlock</li>
|
||||
</ul>
|
||||
|
||||
<li>
|
||||
<b>-lock_max_locks </b>sets the maximum number of locks to <b><i>max </i></b>using
|
||||
the <a href="../../docs/api_c/env_set_lk_max_locks.html">DBENV->set_lk_max_locks</a>
|
||||
method call</li>
|
||||
|
||||
<li>
|
||||
<b>-lock_max_lockers </b>sets the maximum number of locking entities to
|
||||
<b><i>max
|
||||
</i></b>using the <a href="../../docs/api_c/env_set_lk_max_lockers.html">DBENV->set_lk_max_lockers</a>
|
||||
method call</li>
|
||||
|
||||
<li>
|
||||
<b>-lock_max_objects </b>sets the maximum number of simultaneously locked
|
||||
objects to <b><i>max </i></b>using the <a href="../../docs/api_c/env_set_lk_max_objects.html">DBENV->set_lk_max_objects</a>
|
||||
method call</li>
|
||||
|
||||
<li>
|
||||
<b>-lock_timeout </b>sets the timeout for locks in the environment</li>
|
||||
|
||||
<li>
|
||||
<b>-overwrite </b>sets DB_OVERWRITE flag</li>
|
||||
|
||||
<li>
|
||||
<b>-txn_max </b>sets the maximum size of the transaction table to <b><i>max</i></b>
|
||||
using the <a href="../../docs/api_c/env_set_txn_max.html">DBENV->set_txn_max</a>
|
||||
method call</li>
|
||||
|
||||
<li>
|
||||
<b>-txn_timeout </b>sets the timeout for transactions in the environment</li>
|
||||
|
||||
<li>
|
||||
<b>-client_timeout</b> sets the timeout value for the client waiting for
|
||||
a reply from the server for RPC operations to <b><i>seconds</i></b>.</li>
|
||||
|
||||
<li>
|
||||
<b>-server_timeout</b> sets the timeout value for the server to determine
|
||||
an idle client is gone to <b><i>seconds</i></b>.</li>
|
||||
|
||||
<li>
|
||||
<b>-server </b>specifies the <b><i>hostname</i></b> of the server
|
||||
to connect to in the <a href="../../docs/api_c/env_set_server.html">DBENV->set_server</a>
|
||||
call.</li>
|
||||
|
||||
<li>
|
||||
<b>-rep_client </b>sets the newly created environment to be a
|
||||
replication client, using the <a href="../../docs/api_c/rep_client.html">
|
||||
DBENV->rep_client</a> call.</li>
|
||||
|
||||
<li>
|
||||
<b>-rep_master </b>sets the newly created environment to be a
|
||||
replication master, using the <a href="../../docs/api_c/rep_master.html">
|
||||
DBENV->rep_master</a> call.</li>
|
||||
|
||||
<li>
|
||||
<b>-rep_transport </b>specifies the replication transport function,
|
||||
using the
|
||||
<a href="../../docs/api_c/rep_transport.html">DBENV->rep_set_transport</a>
|
||||
call. This site's machine ID is set to <b><i>machineid</i></b> and
|
||||
the send function, a Tcl proc, is set to <b><i>sendproc</i></b>.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
This command will invoke the <a href="../../docs/api_c/env_create.html">db_env_create</a>
|
||||
function. After it successfully gets a handle to an environment,
|
||||
we bind it to a new Tcl command of the form <b><i>envX</i></b>, where X
|
||||
is an integer starting at 0 (e.g. <b>env0, env1, </b>etc).
|
||||
We use the <i>Tcl_CreateObjCommand()</i> to create the top level environment
|
||||
command function. It is through this handle that the user can access
|
||||
all the commands described in the <a href="#Environment Commands">Environment
|
||||
Commands</a> section. Internally, the handle we get back from DB
|
||||
will be stored as the <i>ClientData</i> portion of the new command set
|
||||
so that all future environment calls will have that handle readily available.
|
||||
Then we call the <a href="../../docs/api_c/env_open.html">DBENV->open</a>
|
||||
method call and possibly some number of setup calls as described above.
|
||||
<p>
|
||||
<hr WIDTH="100%">
|
||||
<br><a NAME="> <env> verbose which on|off"></a><b>> <env> verbose <i>which</i>
|
||||
on|off</b>
|
||||
<p>This command controls the use of debugging output for the environment.
|
||||
This command directly translates to a call to the <a href="../../docs/api_c/dbenv_set_verbose.html">DBENV->set_verbose</a>
|
||||
method call. It returns either a 0 (for success), a DB error message
|
||||
or it throws a Tcl error with a system message. The user specifies
|
||||
<b><i>which</i></b>
|
||||
subsystem to control, and indicates whether debug messages should be turned
|
||||
<b>on</b>
|
||||
or <b>off</b> for that subsystem. The value of <b><i>which</i></b>
|
||||
must be one of the following:
|
||||
<ul>
|
||||
<li>
|
||||
<b>deadlock </b>- Chooses the deadlocking code by using the DB_VERB_DEADLOCK
|
||||
value</li>
|
||||
|
||||
<li>
|
||||
<b>recovery </b>- Chooses the recovery code by using the DB_VERB_RECOVERY
|
||||
value</li>
|
||||
|
||||
<li>
|
||||
<b>wait </b>- Chooses the waitsfor code by using the DB_VERB_WAITSFOR value</li>
|
||||
</ul>
|
||||
|
||||
<hr WIDTH="100%">
|
||||
<p><a NAME="> <env> close"></a><b>> <env> close</b>
|
||||
<p>This command closes an environment and deletes the handle. This
|
||||
command directly translates to a call to the <a href="../../docs/api_c/env_close.html">DBENV->close</a>
|
||||
method call. It returns either a 0 (for success), a DB error message
|
||||
or it throws a Tcl error with a system message.
|
||||
<p>Additionally, since the handle is no longer valid, we will call <i>Tcl_DeleteCommand()
|
||||
</i>so
|
||||
that further uses of the handle will be dealt with properly by Tcl itself.
|
||||
<p>Also, the close command will automatically abort any <a href="txn.html">transactions</a>
|
||||
and close any <a href="mpool.html">mpool</a> memory files. As such
|
||||
we must maintain a list of open transaction and mpool handles so that we
|
||||
can call <i>Tcl_DeleteCommand</i> on those as well.
|
||||
<p>
|
||||
<hr WIDTH="100%">
|
||||
|
||||
<b>> berkdb envremove<br>
|
||||
[-data_dir <i>directory</i>]<br>
|
||||
[-force]<br>
|
||||
[-home <i>directory</i>]<br>
|
||||
[-log_dir <i>directory</i>]<br>
|
||||
[-overwrite]<br>
|
||||
[-tmp_dir <i>directory</i>]<br>
|
||||
[-use_environ]<br>
|
||||
[-use_environ_root]</b>
|
||||
|
||||
<p>This command removes the environment if it is not in use and deletes
|
||||
the handle. This command directly translates to a call to the <a href="../../docs/api_c/env_remove.html">DBENV->remove</a>
|
||||
method call. It returns either a 0 (for success), a DB error message
|
||||
or it throws a Tcl error with a system message. The arguments are:
|
||||
<ul>
|
||||
<li>
|
||||
<b>-force</b> selects the DB_FORCE flag to remove even if other processes
|
||||
have the environment open</li>
|
||||
|
||||
<li>
|
||||
<b>-home <i>directory</i> </b>specifies the home directory of the environment</li>
|
||||
|
||||
<li>
|
||||
<b>-data_dir <i>directory </i></b>selects the data file directory of the
|
||||
environment by calling <a href="../../docs/api_c/env_set_data_dir.html">DBENV->set_data_dir</a>.</li>
|
||||
|
||||
<li>
|
||||
<b>-log_dir <i>directory </i></b>selects the log file directory of the
|
||||
environment by calling <a href="../../docs/api_c/env_set_lg_dir.html">DBENV->set_lg_dir</a>.</li>
|
||||
|
||||
<li>
|
||||
<b>-overwrite </b>sets DB_OVERWRITE flag</li>
|
||||
|
||||
<li>
|
||||
<b>-tmp_dir <i>directory </i></b>selects the temporary file directory of
|
||||
the environment by calling <a href="../../docs/api_c/env_set_tmp_dir.so">DBENV->set_tmp_dir</a>.</li>
|
||||
|
||||
<li>
|
||||
<b>-use_environ </b>selects the DB_USE_ENVIRON flag to affect file naming</li>
|
||||
|
||||
<li>
|
||||
<b>-use_environ_root</b> selects the DB_USE_ENVIRON_ROOT flag to affect
|
||||
file naming</li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
168
tcl/docs/historic.html
Normal file
168
tcl/docs/historic.html
Normal file
@@ -0,0 +1,168 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.08 [en] (X11; I; FreeBSD 2.2.8-19990120-SNAP i386) [Netscape]">
|
||||
</HEAD>
|
||||
<BODY>
|
||||
|
||||
<H2>
|
||||
<A NAME="Compatibility Commands"></A>Compatibility Commands</H2>
|
||||
The compatibility commands for old Dbm and Ndbm are described in the <A HREF="../../docs/api_c/dbm.html">dbm</A>
|
||||
manpage.
|
||||
<P><B>> berkdb dbminit <I>filename</I></B>
|
||||
<P>This command will invoke the dbminit function. <B><I>Filename</I></B>
|
||||
is used as the name of the database.
|
||||
<P>
|
||||
<HR WIDTH="100%"><B>> berkdb dbmclose</B>
|
||||
<P>This command will invoke the dbmclose function.
|
||||
<P>
|
||||
<HR WIDTH="100%"><B>> berkdb fetch <I>key</I></B>
|
||||
<P>This command will invoke the fetch function. It will return
|
||||
the data associated with the given <B><I>key </I></B>or a Tcl error.
|
||||
<P>
|
||||
<HR WIDTH="100%"><B>> berkdb store <I>key data</I></B>
|
||||
<P>This command will invoke the store function. It will store
|
||||
the <B><I>key/data</I></B> pair. It will return a 0 on success or
|
||||
throw a Tcl error.
|
||||
<P>
|
||||
<HR WIDTH="100%"><B>> berkdb delete <I>key</I></B>
|
||||
<P>This command will invoke the deletet function. It will delete
|
||||
the <B><I>key</I></B> from the database. It will return a 0 on success
|
||||
or throw a Tcl error.
|
||||
<P>
|
||||
<HR WIDTH="100%"><B>> berkdb firstkey</B>
|
||||
<P>This command will invoke the firstkey function. It will
|
||||
return the first key in the database or a Tcl error.
|
||||
<P>
|
||||
<HR WIDTH="100%"><B>> berkdb nextkey <I>key</I></B>
|
||||
<P>This command will invoke the nextkey function. It will return
|
||||
the next key after the given <B><I>key</I></B> or a Tcl error.
|
||||
<P>
|
||||
<HR WIDTH="100%"><B>> berkdb hcreate <I>nelem</I></B>
|
||||
<P>This command will invoke the hcreate function with <B><I>nelem</I></B>
|
||||
elements. It will return a 0 on success or a Tcl error.
|
||||
<P>
|
||||
<HR WIDTH="100%"><B>> berkdb hsearch <I>key data action</I></B>
|
||||
<P>This command will invoke the hsearch function with <B><I>key</I></B>
|
||||
and <B><I>data</I></B>. The <B><I>action</I></B> must be either <B>find</B>
|
||||
or <B>enter</B>. If it is <B>find</B>, it will return the resultant
|
||||
data. If it is <B>enter</B>, it will return a 0 on success or a Tcl
|
||||
error.
|
||||
<P>
|
||||
<HR WIDTH="100%"><B>> berkdb hdestroy</B>
|
||||
<P>This command will invoke the hdestroy function. It will return
|
||||
a 0.
|
||||
<HR WIDTH="100%"><B>> berkdb ndbm_open [-create] [-rdonly] [-truncate]
|
||||
[-mode
|
||||
<I>mode</I>] [--] <I>filename</I></B>
|
||||
<P>This command will invoke the dbm_open function. After
|
||||
it successfully gets a handle to a database, we bind it to a new Tcl command
|
||||
of the form <B><I>ndbmX, </I></B>where X is an integer starting at 0 (e.g.
|
||||
<B>ndbm0,
|
||||
ndbm1, </B>etc). We use the <I>Tcl_CreateObjCommand() </I> to
|
||||
create the top level database function. It is through this handle
|
||||
that the user can access all of the commands described below. Internally,
|
||||
the database handle is sent as the <I>ClientData</I> portion of the new
|
||||
command set so that all future database calls access the appropriate handle.
|
||||
<P>The arguments are:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>-- </B>- Terminate the list of options and use remaining arguments as
|
||||
the file or subdb names (thus allowing the use of filenames beginning with
|
||||
a dash '-')</LI>
|
||||
|
||||
<LI>
|
||||
<B>-create</B> selects the O_CREAT flag to create underlying files</LI>
|
||||
|
||||
<LI>
|
||||
<B>-rdonly</B> selects the O_RDONLY flag for opening in read-only mode</LI>
|
||||
|
||||
<LI>
|
||||
<B>-truncate</B> selects the O_TRUNC flag to truncate the database</LI>
|
||||
|
||||
<LI>
|
||||
<B>-mode<I> mode</I></B> specifies the mode for created files</LI>
|
||||
|
||||
<LI>
|
||||
<B><I>filename</I></B> indicates the name of the database</LI>
|
||||
</UL>
|
||||
|
||||
<P><BR>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <ndbm> close</B>
|
||||
<P>This command closes the database and renders the handle invalid.
|
||||
This command directly translates to the dbm_close function call.
|
||||
It returns either a 0 (for success), or it throws a Tcl error with
|
||||
a system message.
|
||||
<P>Additionally, since the handle is no longer valid, we will call <I>Tcl_DeleteCommand()
|
||||
</I>so
|
||||
that further uses of the handle will be dealt with properly by Tcl itself.
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <ndbm> clearerr</B>
|
||||
<P>This command clears errors the database. This command
|
||||
directly translates to the dbm_clearerr function call. It returns
|
||||
either a 0 (for success), or it throws a Tcl error with a system
|
||||
message.
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <ndbm> delete <I>key</I></B>
|
||||
<P>This command deletes the <B><I>key</I></B> from thedatabase.
|
||||
This command directly translates to the dbm_delete function call.
|
||||
It returns either a 0 (for success), or it throws a Tcl error with
|
||||
a system message.
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <ndbm> dirfno</B>
|
||||
<P>This command directly translates to the dbm_dirfno function call.
|
||||
It returns either resultts, or it throws a Tcl error with a system
|
||||
message.
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <ndbm> error</B>
|
||||
<P>This command returns the last error. This command directly
|
||||
translates to the dbm_error function call. It returns an error string..
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <ndbm> fetch <I>key</I></B>
|
||||
<P>This command gets the given <B><I>key</I></B> from the database.
|
||||
This command directly translates to the dbm_fetch function call.
|
||||
It returns either the data, or it throws a Tcl error with a system
|
||||
message.
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <ndbm> firstkey</B>
|
||||
<P>This command returns the first key in the database. This
|
||||
command directly translates to the dbm_firstkey function call. It
|
||||
returns either the key, or it throws a Tcl error with a system message.
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <ndbm> nextkey</B>
|
||||
<P>This command returns the next key in the database. This
|
||||
command directly translates to the dbm_nextkey function call. It
|
||||
returns either the key, or it throws a Tcl error with a system message.
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <ndbm> pagfno</B>
|
||||
<P>This command directly translates to the dbm_pagfno function call.
|
||||
It returns either resultts, or it throws a Tcl error with a system
|
||||
message.
|
||||
<BR>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <ndbm> rdonly</B>
|
||||
<P>This command changes the database to readonly. This command
|
||||
directly translates to the dbm_rdonly function call. It returns either
|
||||
a 0 (for success), or it throws a Tcl error with a system message.
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <ndbm> store <I>key data </I>insert|replace</B>
|
||||
<P>This command puts the given <B><I>key</I></B> and <B><I>data</I></B>
|
||||
pair into the database. This command directly translates to
|
||||
the dbm_store function call. It will either <B>insert</B> or <B>replace</B>
|
||||
the data based on the action given in the third argument. It returns
|
||||
either a 0 (for success), or it throws a Tcl error with a system
|
||||
message.
|
||||
<BR>
|
||||
<HR WIDTH="100%">
|
||||
</BODY>
|
||||
</HTML>
|
||||
50
tcl/docs/index.html
Normal file
50
tcl/docs/index.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.08 [en] (X11; I; FreeBSD 2.2.8-19990120-SNAP i386) [Netscape]">
|
||||
</HEAD>
|
||||
<BODY>
|
||||
|
||||
<CENTER>
|
||||
<H1>
|
||||
Complete Tcl Interface for Berkeley DB</H1></CENTER>
|
||||
|
||||
<UL type=disc>
|
||||
<LI>
|
||||
<A HREF="../../docs/api_tcl/tcl_index.html">General use Berkeley DB commands</A></LI>
|
||||
</UL>
|
||||
|
||||
<UL type=disc>
|
||||
<LI>
|
||||
<A HREF="./env.html">Environment commands</A></LI>
|
||||
|
||||
<LI>
|
||||
<A HREF="./lock.html">Locking commands</A></LI>
|
||||
|
||||
<LI>
|
||||
<A HREF="./log.html">Logging commands</A></LI>
|
||||
|
||||
<LI>
|
||||
<A HREF="./mpool.html">Memory Pool commands</A></LI>
|
||||
|
||||
<LI>
|
||||
<A HREF="./rep.html">Replication commands</A></LI>
|
||||
|
||||
<LI>
|
||||
<A HREF="./txn.html">Transaction commands</A></LI>
|
||||
</UL>
|
||||
|
||||
<UL>
|
||||
<LI>
|
||||
<A HREF="./db.html">Access Method commands</A></LI>
|
||||
|
||||
<LI>
|
||||
<A HREF="./test.html">Debugging and Testing</A></LI>
|
||||
|
||||
<LI>
|
||||
<A HREF="./historic.html">Compatibility commands</A></LI>
|
||||
|
||||
<LI>
|
||||
<A HREF="./library.html">Convenience commands</A></LI>
|
||||
</UL>
|
||||
26
tcl/docs/library.html
Normal file
26
tcl/docs/library.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.08 [en] (X11; I; FreeBSD 2.2.8-19990120-SNAP i386) [Netscape]">
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<HR WIDTH="100%">
|
||||
<H2>
|
||||
<A NAME="Convenience Commands"></A>Convenience Commands</H2>
|
||||
The convenience commands are provided for ease of use with the DB test
|
||||
suite.
|
||||
<P><B>> berkdb rand</B>
|
||||
<P>This command will invoke the rand function and return the random number.
|
||||
<P>
|
||||
<HR WIDTH="100%"><B>> berkdb random_int <I>low high</I></B>
|
||||
<P>This command will invoke the rand function and return a number between
|
||||
<B><I>low</I></B>
|
||||
and <B><I>high</I></B>.
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
<P><B>> berkdb srand <I>seed</I></B>
|
||||
<P>This command will invoke the srand function with the given <B><I>seed</I></B>
|
||||
and return 0.
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
206
tcl/docs/lock.html
Normal file
206
tcl/docs/lock.html
Normal file
@@ -0,0 +1,206 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.75 [en] (X11; U; Linux 2.2.16-22 i686) [Netscape]">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>
|
||||
<a NAME="Locking Commands"></a>Locking Commands</h2>
|
||||
Most locking commands work with the environment handle. However,
|
||||
when a user gets a lock we create a new lock handle that they then use
|
||||
with in a similar manner to all the other handles to release the lock.
|
||||
We present the general locking functions first, and then those that manipulate
|
||||
locks.
|
||||
<p><b>> <env> lock_detect [default|oldest|youngest|random]</b>
|
||||
<p>This command runs the deadlock detector. It directly translates
|
||||
to the <a href="../../docs/api_c/lock_detect.html">lock_detect</a> DB call.
|
||||
It returns either a 0 (for success), a DB error message or it throws a
|
||||
Tcl error with a system message. The first argument sets the policy
|
||||
for deadlock as follows:
|
||||
<ul>
|
||||
<li>
|
||||
<b>default</b> selects the DB_LOCK_DEFAULT policy for default detection
|
||||
(default if not specified)</li>
|
||||
|
||||
<li>
|
||||
<b>oldest </b>selects DB_LOCK_OLDEST to abort the oldest locker on a deadlock</li>
|
||||
|
||||
<li>
|
||||
<b>random</b> selects DB_LOCK_RANDOM to abort a random locker on a deadlock</li>
|
||||
|
||||
<li>
|
||||
<b>youngest</b> selects DB_LOCK_YOUNGEST to abort the youngest locker on
|
||||
a deadlock</li>
|
||||
</ul>
|
||||
|
||||
<hr WIDTH="100%">
|
||||
<br><b>> <env> lock_stat</b>
|
||||
<p>This command returns a list of name/value pairs where the names correspond
|
||||
to the C-structure field names of DB_LOCK_STAT and the values are the data
|
||||
returned. This command is a direct translation of the <a href="../../docs/api_c/lock_stat.html">lock_stat</a>
|
||||
DB call.
|
||||
<hr WIDTH="100%">
|
||||
<br><a NAME="> <env> lock_id"></a><b>> <env> lock_id</b>
|
||||
<p>This command returns a unique locker ID value. It directly translates
|
||||
to the <a href="../../docs/api_c/lock_id.html">lock_id</a> DB call.
|
||||
<br>
|
||||
<hr WIDTH="100%">
|
||||
<br><a NAME="> <env> lock_id"></a><b>> <env> lock_id_free </b><i>locker</i>
|
||||
<p>This command frees the locker allockated by the lock_id call. It directly
|
||||
translates to the <a href="../../docs/api_c/lock_id.html">lock_id_free
|
||||
</a>DB
|
||||
call.
|
||||
<hr WIDTH="100%">
|
||||
<br><a NAME="> <env> lock_id"></a><b>> <env> lock_id_set </b><i>current
|
||||
max</i>
|
||||
<p>This is a diagnostic command to set the locker id that will get
|
||||
allocated next and the maximum id that
|
||||
<br>will trigger the id reclaim algorithm.
|
||||
<hr WIDTH="100%">
|
||||
<br><a NAME="> <env> lock_get"></a><b>> <env> lock_get [-nowait]<i>lockmode
|
||||
locker obj</i></b>
|
||||
<p>This command gets a lock. It will invoke the <a href="../../docs/api_c/lock_get.html">lock_get</a>
|
||||
function. After it successfully gets a handle to a lock, we bind
|
||||
it to a new Tcl command of the form <b><i>$env.lockX</i></b>, where X is
|
||||
an integer starting at 0 (e.g. <b>$env.lock0, $env.lock1, </b>etc).
|
||||
We use the <i>Tcl_CreateObjCommand()</i> to create the top level locking
|
||||
command function. It is through this handle that the user can release
|
||||
the lock. Internally, the handle we get back from DB will be stored
|
||||
as the <i>ClientData</i> portion of the new command set so that future
|
||||
locking calls will have that handle readily available.
|
||||
<p>The arguments are:
|
||||
<ul>
|
||||
<li>
|
||||
<b><i>locker</i></b> specifies the locker ID returned from the <a href="#> <env> lock_id">lock_id</a>
|
||||
command</li>
|
||||
|
||||
<li>
|
||||
<b><i>obj</i></b> specifies an object to lock</li>
|
||||
|
||||
<li>
|
||||
the <b><i>lock mode</i></b> is specified as one of the following:</li>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>ng </b>specifies DB_LOCK_NG for not granted (always 0)</li>
|
||||
|
||||
<li>
|
||||
<b>read</b> specifies DB_LOCK_READ for a read (shared) lock</li>
|
||||
|
||||
<li>
|
||||
<b>write</b> specifies DB_LOCK_WRITE for an exclusive write lock</li>
|
||||
|
||||
<li>
|
||||
<b>iwrite </b>specifies DB_LOCK_IWRITE for intent for exclusive write lock</li>
|
||||
|
||||
<li>
|
||||
<b>iread </b>specifies DB_LOCK_IREAD for intent for shared read lock</li>
|
||||
|
||||
<li>
|
||||
<b>iwr </b>specifies DB_LOCK_IWR for intent for eread and write lock</li>
|
||||
</ul>
|
||||
|
||||
<li>
|
||||
<b>-nowait</b> selects the DB_LOCK_NOWAIT to indicate that we do not want
|
||||
to wait on the lock</li>
|
||||
</ul>
|
||||
|
||||
<hr WIDTH="100%">
|
||||
<br><b>> <lock> put</b>
|
||||
<p>This command releases the lock referenced by the command. It is
|
||||
a direct translation of the <a href="../../docs/api_c/lock_put.html">lock_put</a>
|
||||
function. It returns either a 0 (for success), a DB error message
|
||||
or it throws a Tcl error with a system message. Additionally, since
|
||||
the handle is no longer valid, we will call
|
||||
<i>Tcl_DeleteCommand()
|
||||
</i>so
|
||||
that further uses of the handle will be dealt with properly by Tcl itself.
|
||||
<br>
|
||||
<hr WIDTH="100%">
|
||||
<br><a NAME="> <env> lock_vec"></a><b>> <env> lock_vec [-nowait] <i>locker
|
||||
</i>{get|put|put_all|put_obj
|
||||
[<i>obj</i>] [<i>lockmode</i>] [<i>lock</i>]} ...</b>
|
||||
<p>This command performs a series of lock calls. It is a direct translation
|
||||
of the <a href="../../docs/api_c/lock_vec.html">lock_vec</a> function.
|
||||
This command will return a list of the return values from each operation
|
||||
specified in the argument list. For the 'put' operations the entry
|
||||
in the return value list is either a 0 (for success) or an error.
|
||||
For the 'get' operation, the entry is the lock widget handle, <b>$env.lockN</b>
|
||||
(as described above in <a href="#> <env> lock_get"><env> lock_get</a>)
|
||||
or an error. If an error occurs, the return list will contain the
|
||||
return values for all the successful operations up the erroneous one and
|
||||
the error code for that operation. Subsequent operations will be
|
||||
ignored.
|
||||
<p>As for the other operations, if we are doing a 'get' we will create
|
||||
the commands and if we are doing a 'put' we will have to delete the commands.
|
||||
Additionally, we will have to do this after the call to the DB lock_vec
|
||||
and iterate over the results, creating and/or deleting Tcl commands.
|
||||
It is possible that we may return a lock widget from a get operation that
|
||||
is considered invalid, if, for instance, there was a <b>put_all</b> operation
|
||||
performed later in the vector of operations. The arguments are:
|
||||
<ul>
|
||||
<li>
|
||||
<b><i>locker</i></b> specifies the locker ID returned from the <a href="#> <env> lock_id">lock_id</a>
|
||||
command</li>
|
||||
|
||||
<li>
|
||||
<b>-nowait</b> selects the DB_LOCK_NOWAIT to indicate that we do not want
|
||||
to wait on the lock</li>
|
||||
|
||||
<li>
|
||||
the lock vectors are tuple consisting of {an operation, lock object, lock
|
||||
mode, lock handle} where what is required is based on the operation desired:</li>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>get</b> specifes DB_LOCK_GET to get a lock. Requires a tuple <b>{get
|
||||
<i>objmode</i>}
|
||||
</b>where
|
||||
<b><i>mode</i></b>
|
||||
is:</li>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>ng </b>specifies DB_LOCK_NG for not granted (always 0)</li>
|
||||
|
||||
<li>
|
||||
<b>read</b> specifies DB_LOCK_READ for a read (shared) lock</li>
|
||||
|
||||
<li>
|
||||
<b>write</b> specifies DB_LOCK_WRITE for an exclusive write lock</li>
|
||||
|
||||
<li>
|
||||
<b>iwrite </b>specifies DB_LOCK_IWRITE for intent for exclusive write lock</li>
|
||||
|
||||
<li>
|
||||
<b>iread </b>specifies DB_LOCK_IREAD for intent for shared read lock</li>
|
||||
|
||||
<li>
|
||||
<b>iwr </b>specifies DB_LOCK_IWR for intent for eread and write lock</li>
|
||||
</ul>
|
||||
|
||||
<li>
|
||||
<b>put</b> specifies DB_LOCK_PUT to release a <b><i>lock</i></b>.
|
||||
Requires a tuple <b>{put <i>lock}</i></b></li>
|
||||
|
||||
<li>
|
||||
<b>put_all </b>specifies DB_LOCK_PUT_ALL to release all locks held by <b><i>locker</i></b>.
|
||||
Requires a tuple <b>{put_all}</b></li>
|
||||
|
||||
<li>
|
||||
<b>put_obj</b> specifies DB_LOCK_PUT_OBJ to release all locks held by <b><i>locker</i></b>
|
||||
associated with the given <b><i>obj</i></b>. Requires a tuple <b>{put_obj
|
||||
<i>obj}</i></b></li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<hr WIDTH="100%">
|
||||
<br><a NAME="> <env> lock_vec"></a><b>> <env> lock_timeout <i>timeout</i></b>
|
||||
<p>This command sets the lock timeout for all future locks in this environment.
|
||||
The timeout is in micorseconds.
|
||||
<br>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
123
tcl/docs/log.html
Normal file
123
tcl/docs/log.html
Normal file
@@ -0,0 +1,123 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.08 [en] (X11; I; FreeBSD 3.3-RELEASE i386) [Netscape]">
|
||||
</HEAD>
|
||||
<BODY>
|
||||
|
||||
<H2>
|
||||
<A NAME="Logging Commands"></A>Logging Commands</H2>
|
||||
Logging commands work from the environment handle to control the use of
|
||||
the log files. Log files are opened when the environment is opened
|
||||
and closed when the environment is closed. In all of the commands
|
||||
in the logging subsystem that take or return a log sequence number, it
|
||||
is of the form:
|
||||
<BR><B>{<I>fileid offset</I>}</B>
|
||||
<BR>where the <B><I>fileid</I></B> is an identifier of the log file, as
|
||||
returned from the <A HREF="#> <env> log_get">log_get</A> call.
|
||||
<P><B>> <env> log_archive [-arch_abs] [-arch_data] [-arch_log]</B>
|
||||
<P>This command returns a list of log files that are no longer in
|
||||
use. It is a direct call to the <A HREF="../../docs/api_c/log_archive.html">log_archive</A>
|
||||
function. The arguments are:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>-arch_abs </B>selects DB_ARCH_ABS to return all pathnames as absolute
|
||||
pathnames</LI>
|
||||
|
||||
<LI>
|
||||
<B>-arch_data </B>selects DB_ARCH_DATA to return a list of database files</LI>
|
||||
|
||||
<LI>
|
||||
<B>-arch_log </B>selects DB_ARCH_LOG to return a list of log files</LI>
|
||||
</UL>
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <env> log_compare <I>lsn1 lsn2</I></B>
|
||||
<P>This command compares two log sequence numbers, given as <B><I>lsn1</I></B>
|
||||
and <B><I>lsn2</I></B>. It is a direct call to the <A HREF="../../docs/api_c/log_compare.html">log_compare</A>
|
||||
function. It will return a -1, 0, 1 to indicate if <B><I>lsn1</I></B>
|
||||
is less than, equal to or greater than <B><I>lsn2</I></B> respectively.
|
||||
<BR>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <env> log_file <I>lsn</I></B>
|
||||
<P>This command returns the file name associated with the given <B><I>lsn</I></B>.
|
||||
It is a direct call to the <A HREF="../../docs/api_c/log_file.html">log_file</A>
|
||||
function.
|
||||
<BR>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <env> log_flush [<I>lsn</I>]</B>
|
||||
<P>This command flushes the log up to the specified <B><I>lsn</I></B>
|
||||
or flushes all records if none is given It is a direct call to the
|
||||
<A HREF="../../docs/api_c/log_flush.html">log_flush</A>
|
||||
function. It returns either a 0 (for success), a DB error message
|
||||
or it throws a Tcl error with a system message.
|
||||
<BR>
|
||||
<HR WIDTH="100%">
|
||||
<BR><A NAME="<env> log_get"></A><B>> <env> log_get<I> </I>[-checkpoint]
|
||||
[-current] [-first] [-last] [-next] [-prev] [-set <I>lsn</I>]</B>
|
||||
<P>This command retrieves a record from the log according to the <B><I>lsn</I></B>
|
||||
given and returns it and the data. It is a direct call to the <A HREF="../../docs/api_c/log_get.html">log_get</A>
|
||||
function. It is a way of implementing a manner of log iteration similar
|
||||
to <A HREF="../../docs/api_tcl/db_cursor.html">cursors</A>.
|
||||
The information we return is similar to database information. We
|
||||
return a list where the first item is the LSN (which is a list itself)
|
||||
and the second item is the data. So it looks like, fully expanded,
|
||||
<B>{{<I>fileid</I>
|
||||
<I>offset</I>}
|
||||
<I>data</I>}.</B>
|
||||
In the case where DB_NOTFOUND is returned, we return an empty list <B>{}</B>.
|
||||
All other errors return a Tcl error. The arguments are:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>-checkpoint </B>selects the DB_CHECKPOINT flag to return the LSN/data
|
||||
pair of the last record written through <A HREF="#> <env> log_put">log_put</A>
|
||||
with DB_CHECKPOINT specified</LI>
|
||||
|
||||
<LI>
|
||||
<B>-current</B> selects the DB_CURRENT flag to return the current record</LI>
|
||||
|
||||
<LI>
|
||||
<B>-first</B> selects the DB_FIRST flag to return the first record in the
|
||||
log.</LI>
|
||||
|
||||
<LI>
|
||||
<B>-last </B>selects the DB_LAST flag to return the last record in the
|
||||
log.</LI>
|
||||
|
||||
<LI>
|
||||
<B>-next</B> selects the DB_NEXT flag to return the next record in the
|
||||
log.</LI>
|
||||
|
||||
<LI>
|
||||
<B>-prev </B>selects the DB_PREV flag to return the previous record
|
||||
in the log.</LI>
|
||||
|
||||
<LI>
|
||||
<B>-set</B> selects the DB_SET flag to return the record specified by the
|
||||
given <B><I>lsn</I></B></LI>
|
||||
</UL>
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<BR><A NAME="> <env> log_put"></A><B>> <env> log_put<I> </I>[-checkpoint]
|
||||
[-flush] <I>record</I></B>
|
||||
<P>This command stores a <B><I>record</I></B> into the log and returns
|
||||
the LSN of the log record. It is a direct call to the <A HREF="../../docs/api_c/log_put.html">log_put</A>
|
||||
function. It returns either an LSN or it throws a Tcl error with
|
||||
a system message. <B> </B>The arguments are:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>-checkpoint </B>selects the DB_CHECKPOINT flag</LI>
|
||||
|
||||
<LI>
|
||||
<B>-flush </B>selects the DB_FLUSH flag to flush the log to disk.</LI>
|
||||
</UL>
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <env> log_stat</B>
|
||||
<P>This command returns the statistics associated with the logging
|
||||
subsystem. It is a direct call to the <A HREF="../../docs/api_c/log_stat.html">log_stat</A>
|
||||
function. It returns a list of name/value pairs of the DB_LOG_STAT
|
||||
structure.
|
||||
</BODY>
|
||||
</HTML>
|
||||
189
tcl/docs/mpool.html
Normal file
189
tcl/docs/mpool.html
Normal file
@@ -0,0 +1,189 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.08 [en] (X11; I; FreeBSD 2.2.8-19990120-SNAP i386) [Netscape]">
|
||||
</HEAD>
|
||||
<BODY>
|
||||
|
||||
<H2>
|
||||
<A NAME="Memory Pool Commands"></A>Memory Pool Commands</H2>
|
||||
Memory pools are used in a manner similar to the other subsystems.
|
||||
We create a handle to the pool and then use it for a variety of operations.
|
||||
Some of the memory pool commands use the environment instead. Those are
|
||||
presented first.
|
||||
<P><B>> <env> mpool_stat</B>
|
||||
<P>This command returns the statistics associated with the memory
|
||||
pool subsystem. It is a direct call to the <A HREF="../../docs/api_c/memp_stat.html">memp_stat</A>
|
||||
function. It returns a list of name/value pairs of the DB_MPOOL_STAT
|
||||
structure.
|
||||
<BR>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <env> mpool_sync <I>lsn</I></B>
|
||||
<P>This command flushes the memory pool for all pages with a log sequence
|
||||
number less than <B><I>lsn</I></B>. It is a direct call to the <A HREF="../../docs/api_c/memp_sync.html">memp_sync </A>
|
||||
function. It returns either a 0 (for success), a DB error message
|
||||
or it throws a Tcl error with a system message.
|
||||
<BR>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <env> mpool_trickle <I>percent</I></B>
|
||||
<P>This command tells DB to ensure that at least <B><I>percent</I></B>
|
||||
percent of the pages are clean by writing out enough to dirty pages to
|
||||
achieve that percentage. It is a direct call to the <A HREF="../../docs/api_c/memp_trickle.html">memp_trickle</A>
|
||||
function. The command will return the number of pages actually written.
|
||||
It returns either the number of pages on success, or it throws a Tcl error
|
||||
with a system message.
|
||||
<BR>
|
||||
<HR WIDTH="100%">
|
||||
<P><B>> <env> mpool [-create] [-nommap] [-rdonly] [-mode <I>mode</I>]
|
||||
-pagesize <I>size</I> [<I>file</I>]</B>
|
||||
<P>This command creates a new memory pool. It invokes the <A HREF="../../docs/api_c/memp_fopen.html">memp_fopen</A>
|
||||
function. After it successfully gets a handle to a memory pool, we
|
||||
bind it to a new Tcl command of the form <B><I>$env.mpX</I></B>, where
|
||||
X is an integer starting at 0 (e.g. <B>$env.mp0, $env.mp1, </B>etc).
|
||||
We use the <I>Tcl_CreateObjCommand()</I> to create the top level memory
|
||||
pool functions. It is through this handle that the user can manipulate
|
||||
the pool. Internally, the handle we get back from DB will be stored
|
||||
as the <I>ClientData</I> portion of the new command set so that future
|
||||
memory pool calls will have that handle readily available. Additionally,
|
||||
we need to maintain this handle in relation to the environment so that
|
||||
if the user calls <A HREF="../../docs/api_tcl/env_close.html"><env> close</A> without closing
|
||||
the memory pool we can properly clean up. The arguments are:
|
||||
<UL>
|
||||
<LI>
|
||||
<B><I>file</I></B> is the name of the file to open</LI>
|
||||
|
||||
<LI>
|
||||
<B>-create </B>selects the DB_CREATE flag to create underlying file</LI>
|
||||
|
||||
<LI>
|
||||
<B>-mode <I>mode </I></B>sets the permissions of created file to <B><I>mode</I></B></LI>
|
||||
|
||||
<LI>
|
||||
<B>-nommap</B> selects the DB_NOMMAP flag to disallow using mmap'ed files</LI>
|
||||
|
||||
<LI>
|
||||
<B>-pagesize</B> sets the underlying file page size to <B><I>size</I></B></LI>
|
||||
|
||||
<LI>
|
||||
<B>-rdonly </B>selects the DB_RDONLY flag for read only access</LI>
|
||||
</UL>
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <mp> close</B>
|
||||
<P>This command closes the memory pool. It is a direct call to the
|
||||
<A HREF="../../docs/api_c/memp_fclose.html">memp_close</A>
|
||||
function. It returns either a 0 (for success), a DB error message
|
||||
or it throws a Tcl error with a system message.
|
||||
<P>Additionally, since the handle is no longer valid, we will call
|
||||
<I>Tcl_DeleteCommand()
|
||||
</I>so
|
||||
that further uses of the handle will be dealt with properly by Tcl itself.
|
||||
We must also remove the reference to this handle from the environment.
|
||||
We will go through the list of pinned pages that were acquired by the <A HREF="#> <mp> get">get</A>
|
||||
command and
|
||||
<A HREF="#> <pg> put">put</A> them back.
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <mp> fsync</B>
|
||||
<P>This command flushes all of the file's dirty pages to disk. It
|
||||
is a direct call to the <A HREF="../../docs/api_c/memp_fsync.html">memp_fsync</A>
|
||||
function. It returns either a 0 (for success), a DB error message
|
||||
or it throws a Tcl error with a system message.
|
||||
<HR WIDTH="100%">
|
||||
<BR><A NAME="> <mp> get"></A><B>> <mp> get [-create] [-last] [-new]
|
||||
[<I>pgno</I>]</B>
|
||||
<P>This command gets the <B><I>pgno </I></B>page from the memory
|
||||
pool. It invokes the <A HREF="../../docs/api_c/memp_fget.html">memp_fget</A>
|
||||
function and possibly the <A HREF="../../docs/api_c/memp_fset.html">memp_fset</A>
|
||||
function if any options are chosen to set the page characteristics.
|
||||
After it successfully gets a handle to a page, we bind it to and
|
||||
return a new Tcl command of the form <B><I>$env.mpN.pX</I></B>, where X
|
||||
is an integer starting at 0 (e.g. <B>$env.mp0.p0, $env.mp1.p0, </B>etc).
|
||||
We use the <I>Tcl_CreateObjCommand()</I> to create the top level page functions.
|
||||
It is through this handle that the user can manipulate the page.
|
||||
Internally, the handle we get back from DB will be stored as the <I>ClientData</I>
|
||||
portion of the new command set. We need to store this handle in
|
||||
relation to the memory pool handle so that if the memory pool is closed,
|
||||
we will <A HREF="#> <pg> put">put</A> back the pages (setting the discard
|
||||
flag) and delete that set of commands.
|
||||
<P>The arguments are:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>-create </B>selects the DB_MPOOL_CREATE flag to create the page
|
||||
if it does not exist.</LI>
|
||||
|
||||
<LI>
|
||||
<B>-last</B> selects the DB_MPOOL_LAST flag to return the last page in
|
||||
the file</LI>
|
||||
|
||||
<LI>
|
||||
<B>-new</B> selects the DB_MPOOL_NEW flag to create a new page</LI>
|
||||
</UL>
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <pg> pgnum</B>
|
||||
<P>This command returns the page number associated with this memory pool
|
||||
page. Primarily it will be used after an <A HREF="#> <mp> get"><mp>
|
||||
get</A> call.
|
||||
<BR>
|
||||
<HR WIDTH="100%"><B>> <pg> pgsize</B>
|
||||
<P>This command returns the page size associated with this memory pool
|
||||
page. Primarily it will be used after an <A HREF="#> <mp> get"><mp>
|
||||
get</A> call.
|
||||
<BR>
|
||||
<HR WIDTH="100%"><B>> <pg> set [-clean] [-dirty] [-discard]</B>
|
||||
<P>This command sets the characteristics of the page. It is a direct
|
||||
call to the <A HREF="../../docs/api_c/memp_fset.html">memp_fset</A> function.
|
||||
It returns either a 0 (for success), a DB error message or it throws a
|
||||
Tcl error with a system message. The arguments are:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>-clean</B> selects the DB_MPOOL_CLEAN flag to indicate this is a clean
|
||||
page</LI>
|
||||
|
||||
<LI>
|
||||
<B>-dirty</B> selects the DB_MPOOL_DIRTY flag to indicate this page should
|
||||
be flushed before eviction</LI>
|
||||
|
||||
<LI>
|
||||
<B>-discard</B> selects the DB_MPOOL_DISCARD flag to indicate this page
|
||||
is unimportant</LI>
|
||||
</UL>
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<BR><A NAME="> <pg> put"></A><B>> <pg> put [-clean] [-dirty] [-discard]</B>
|
||||
<P>This command will put back the page to the memory pool. It is
|
||||
a direct call to the <A HREF="../../docs/api_c/memp_fput.html">memp_fput</A>
|
||||
function. It returns either a 0 (for success), a DB error message
|
||||
or it throws a Tcl error with a system message. Additionally, since the
|
||||
handle is no longer valid, we will call
|
||||
<I>Tcl_DeleteCommand()
|
||||
</I>so that
|
||||
further uses of the handle will be dealt with properly by Tcl itself.
|
||||
We must also remove the reference to this handle from the memory pool.
|
||||
<P>The arguments are:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>-clean</B> selects the DB_MPOOL_CLEAN flag to indicate this is a clean
|
||||
page</LI>
|
||||
|
||||
<LI>
|
||||
<B>-dirty</B> selects the DB_MPOOL_DIRTY flag to indicate this page should
|
||||
be flushed before eviction</LI>
|
||||
|
||||
<LI>
|
||||
<B>-discard</B> selects the DB_MPOOL_DISCARD flag to indicate this page
|
||||
is unimportant</LI>
|
||||
</UL>
|
||||
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <pg> init <I>val|string</I></B>
|
||||
<P>This command initializes the page to the <B><I>val</I></B> given or
|
||||
places the <B><I>string</I></B> given at the beginning of the page.
|
||||
It returns a 0 for success or it throws a Tcl error with an error message.
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
<BR><B>> <pg> is_setto <I>val|string</I></B>
|
||||
<P>This command verifies the page contains the <B><I>val</I></B> given
|
||||
or checks that the <B>string</B> given is at the beginning of the page.
|
||||
It returns a 1 if the page is correctly set to the value and a 0 otherwise.
|
||||
50
tcl/docs/rep.html
Normal file
50
tcl/docs/rep.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>Replication commands</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>
|
||||
<a NAME="Replication Commands"></a>Replication Commands</h2>
|
||||
Replication commands are invoked from the environment handle, after
|
||||
it has been opened with the appropriate flags defined
|
||||
<a href="./env.html">here</a>.<br>
|
||||
<hr WIDTH="100%">
|
||||
<p><b>> <env> rep_process_message <i>machid</i> <i>control</i>
|
||||
<i>rec</i></b>
|
||||
<p>This command processes a single incoming replication message. It
|
||||
is a direct translation of the <a
|
||||
href="../../docs/api_c/rep_process_message.html">rep_process_message</a>
|
||||
function.
|
||||
It returns either a 0 (for success), a DB error message or it throws a
|
||||
Tcl error with a system message. The arguments are:
|
||||
<ul>
|
||||
<li>
|
||||
<b>machid </b>is the machine ID of the machine that <i>sent</i> this
|
||||
message.</li>
|
||||
|
||||
<li>
|
||||
<b>control</b> is a binary string containing the exact contents of the
|
||||
<b><i>control</i></b> argument to the <b><i>sendproc</i></b> function
|
||||
that was passed this message on another site.</li>
|
||||
|
||||
<li>
|
||||
<b>rec</b> is a binary string containing the exact contents of the
|
||||
<b><i>rec</i></b> argument to the <b><i>sendproc</i></b> function
|
||||
that was passed this message on another site.</li>
|
||||
</ul>
|
||||
|
||||
<hr WIDTH="100%">
|
||||
<br><b>> <env> rep_elect <i>nsites</i> <i>pri</i> <i>wait</i>
|
||||
<i>sleep</i></b>
|
||||
<p>This command causes a replication election. It is a direct translation
|
||||
of the <a href="../../docs/api_c/rep_elect.html">rep_elect</a> function.
|
||||
Its arguments, all integers, correspond exactly to that C function's
|
||||
parameters.
|
||||
It will return a list containing two integers, which contain,
|
||||
respectively, the integer values returned in the C function's
|
||||
<i><b>midp</b></i> and <i><b>selfp</b></i> parameters.
|
||||
</body>
|
||||
</html>
|
||||
93
tcl/docs/sequence.html
Normal file
93
tcl/docs/sequence.html
Normal file
@@ -0,0 +1,93 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type"
|
||||
content="text/html; charset=ISO-8859-1">
|
||||
<title>Sequence Commands</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2><a name="Database Commands"></a>Sequence Commands</h2>
|
||||
<b>> berkdb sequence [-auto_commit] [-txn txnid] [-create] </b><br>
|
||||
<div style="margin-left: 40px;"> Implements <a
|
||||
href="file:///home/ubell/db.new/docs/seq/seq_open.html">DBENV->sequence</a>
|
||||
function. The above options have the usual meanings.<br>
|
||||
</div>
|
||||
<span style="font-weight: bold;">[-cachesize]</span><br>
|
||||
<div style="margin-left: 40px;">Set the size of the cache in this
|
||||
handle.<br>
|
||||
</div>
|
||||
<span style="font-weight: bold;">[-inc]<br>
|
||||
</span>
|
||||
<div style="margin-left: 40px;">Sequence increments..<br>
|
||||
</div>
|
||||
<span style="font-weight: bold;">[-dec]<br>
|
||||
</span>
|
||||
<div style="margin-left: 40px;">Sequence decrements.<br>
|
||||
</div>
|
||||
<span style="font-weight: bold;">[-init integer]<br>
|
||||
</span>
|
||||
<div style="margin-left: 40px;">Set the initial value for sequence.<br>
|
||||
</div>
|
||||
<span style="font-weight: bold;">[-max integer]</span><br>
|
||||
<div style="margin-left: 40px;">Set the maximum value for the sequence.<br>
|
||||
</div>
|
||||
<span style="font-weight: bold;">[-max integer]<br>
|
||||
</span>
|
||||
<div style="margin-left: 40px;">Set the minimum value for the sequence.<br>
|
||||
</div>
|
||||
<span style="font-weight: bold;">[-wrap]</span><br>
|
||||
<div style="margin-left: 40px;">Wrap around at max or min.<br>
|
||||
</div>
|
||||
<span style="font-weight: bold;"><span style="font-style: italic;">db</span>
|
||||
key<br>
|
||||
</span>
|
||||
<div style="margin-left: 40px;">Database handle and key of sequence.<br>
|
||||
</div>
|
||||
<hr width="100%"><span style="font-style: italic;"><span
|
||||
style="font-weight: bold;">> seq </span></span><span
|
||||
style="font-weight: bold;">get [-txn <span style="font-style: italic;">txn</span>]
|
||||
[-auto_commit] [-nosync] delta<br>
|
||||
</span>
|
||||
<div style="margin-left: 40px;">Get the nexted sequence value and
|
||||
increment the sequence by <span style="font-weight: bold;">delta</span>.<br>
|
||||
</div>
|
||||
<hr width="100%"><span style="font-weight: bold;">> <span
|
||||
style="font-style: italic;">seq </span>close</span><br>
|
||||
<div style="margin-left: 40px;">Close the sequence<br>
|
||||
</div>
|
||||
<br>
|
||||
<hr width="100%"><span style="font-weight: bold;">> <span
|
||||
style="font-style: italic;">seq</span> remove [-auto_commit] [-nosync]
|
||||
[-txn] <br>
|
||||
</span>
|
||||
<div style="margin-left: 40px;">Remove the sequence.<br>
|
||||
</div>
|
||||
<hr width="100%"><span style="font-weight: bold;">> <span
|
||||
style="font-style: italic;">seq </span>get_cachesize<br>
|
||||
</span>
|
||||
<div style="margin-left: 40px;">Return the size of the cache.<br>
|
||||
</div>
|
||||
<hr width="100%"><span style="font-weight: bold;">> <span
|
||||
style="font-style: italic;">seq </span>get_db<br>
|
||||
</span>
|
||||
<div style="margin-left: 40px;">Return the underlying db handle.<br>
|
||||
</div>
|
||||
<hr width="100%"><span style="font-weight: bold;">> <span
|
||||
style="font-style: italic;">seq </span>get_flags</span><br>
|
||||
<div style="margin-left: 40px;">Return the flags set on create.<br>
|
||||
</div>
|
||||
<hr width="100%"><span style="font-weight: bold;">> <span
|
||||
style="font-style: italic;">seq</span> get_range<br>
|
||||
</span>
|
||||
<div style="margin-left: 40px;">Return the min and max set at create.<br>
|
||||
</div>
|
||||
<hr width="100%"><span style="font-weight: bold;">> <span
|
||||
style="font-style: italic;">seq </span>stat<br>
|
||||
</span>
|
||||
<div style="margin-left: 40px;">Implements the <a
|
||||
href="../../docs/seq/seq_stat.html">SEQUENCE->stat</a> function.<br>
|
||||
</div>
|
||||
<hr width="100%">
|
||||
</body>
|
||||
</html>
|
||||
103
tcl/docs/test.html
Normal file
103
tcl/docs/test.html
Normal file
@@ -0,0 +1,103 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.08 [en] (X11; I; FreeBSD 2.2.8-19990120-SNAP i386) [Netscape]">
|
||||
</HEAD>
|
||||
<BODY>
|
||||
|
||||
<H2>
|
||||
<A NAME="Debugging"></A>Debugging and Testing</H2>
|
||||
We have imported the debugging system from the old test suite into the
|
||||
new interface to aid in debugging problems. There are several variables
|
||||
that are available both in gdb as globals to the C code, and variables
|
||||
in Tcl that the user can set. These variables are linked together
|
||||
so that changes in one venue are reflected in the other. The names
|
||||
of the variables have been modified a bit to reduce the likelihood
|
||||
<BR>of namespace trampling. We have added a double underscore to
|
||||
all the names.
|
||||
<P>The variables are all initialized to zero (0) thus resulting in debugging
|
||||
being turned off. The purpose of the debugging, fundamentally, is
|
||||
to allow the user to set a breakpoint prior to making a DB call.
|
||||
This breakpoint is set in the <I>__db_loadme() </I>function. The
|
||||
user may selectively turn on various debugging areas each controlled by
|
||||
a separate variable (note they all have two (2) underscores prepended to
|
||||
the name):
|
||||
<UL>
|
||||
<LI>
|
||||
<B>__debug_on</B> - Turns on the debugging system. This must be on
|
||||
for any debugging to occur</LI>
|
||||
|
||||
<LI>
|
||||
<B>__debug_print - </B>Turns on printing a debug count statement on each
|
||||
call</LI>
|
||||
|
||||
<LI>
|
||||
<B>__debug_test -</B> Hits the breakpoint in <I>__db_loadme</I> on the
|
||||
specific iteration</LI>
|
||||
|
||||
<LI>
|
||||
<B>__debug_stop </B>- Hits the breakpoint in <I>__db_loadme</I> on every
|
||||
(or the next) iteration</LI>
|
||||
</UL>
|
||||
<B>Note to developers:</B> Anyone extending this interface must place
|
||||
a call to <B>_debug_check()</B> (no arguments) before every call into the
|
||||
DB library.
|
||||
<P>There is also a command available that will force a call to the _debug_check
|
||||
function.
|
||||
<P><B>> berkdb debug_check</B>
|
||||
<P>
|
||||
<HR WIDTH="100%">
|
||||
<BR>For testing purposes we have added several hooks into the DB library
|
||||
and a small interface into the environment and/or database commands to
|
||||
manipulate the hooks. This command interface and the hooks and everything
|
||||
that goes with it is only enabled when the test option is configured into
|
||||
DB.
|
||||
<P><B>> <env> test copy <I>location</I></B>
|
||||
<BR><B>> <db> test copy <I>location</I></B>
|
||||
<BR><B>> <env> test abort <I>location</I></B>
|
||||
<BR><B>> <db> test abort <I>location</I></B>
|
||||
<P>In order to test recovery we need to be able to abort the creation or
|
||||
deletion process at various points. Also we want to invoke a copy
|
||||
function to copy the database file(s) at various points as well so
|
||||
that we can obtain before/after snapshots of the databases. The interface
|
||||
provides the test command to specify a <B><I>location</I></B> where we
|
||||
wish to invoke a <B>copy</B> or an <B>abort</B>. The command is available
|
||||
from either the environment or the database for convenience. The
|
||||
<B><I>location</I></B>
|
||||
can be one of the following:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>none -</B> Clears the location</LI>
|
||||
|
||||
<LI>
|
||||
<B>preopen -</B> Sets the location prior to the __os_open call in the creation
|
||||
process</LI>
|
||||
|
||||
<LI>
|
||||
<B>postopen</B> - Sets the location to immediately following the __os_open
|
||||
call in creation</LI>
|
||||
|
||||
<LI>
|
||||
<B>postlogmeta</B> - Sets the location to immediately following the __db_log_page
|
||||
call to log the meta data in creation. Only valid for Btree.</LI>
|
||||
|
||||
<LI>
|
||||
<B>postlog</B> - Sets the location to immediately following the last (or
|
||||
only) __db_log_page call in creation.</LI>
|
||||
|
||||
<LI>
|
||||
<B>postsync</B> - Sets the location to immediately following the sync of
|
||||
the log page in creation.</LI>
|
||||
|
||||
<LI>
|
||||
<B>prerename</B> - Sets the location prior to the __os_rename call in the
|
||||
deletion process.</LI>
|
||||
|
||||
<LI>
|
||||
<B>postrename</B> - Sets the location to immediately following the __os_rename
|
||||
call in deletion</LI>
|
||||
</UL>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
69
tcl/docs/txn.html
Normal file
69
tcl/docs/txn.html
Normal file
@@ -0,0 +1,69 @@
|
||||
<!--Copyright 1999,2008 Oracle. All rights reserved.-->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.75 [en] (X11; U; Linux 2.2.16-22 i686) [Netscape]">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>
|
||||
<a NAME="Transaction Commands"></a>Transaction Commands</h2>
|
||||
Transactions are used in a manner similar to the other subsystems.
|
||||
We create a handle to the transaction and then use it for a variety
|
||||
of operations. Some of the transaction commands use the environment
|
||||
instead. Those are presented first. The transaction command
|
||||
handle returned is the handle used by the various commands that can be
|
||||
transaction protected, such as <a href="../../docs/api_tcl/db_cursor.html">cursors</a>.
|
||||
<br>
|
||||
<hr WIDTH="100%">
|
||||
<p><b>> <env> txn_checkpoint [-kbyte <i>kb</i>] [-min <i>min</i>]</b>
|
||||
<p>This command causes a checkpoint of the transaction region. It
|
||||
is a direct translation of the <a href="../../docs/api_c/txn_checkpoint.html">txn_checkpoint
|
||||
</a>function.
|
||||
It returns either a 0 (for success), a DB error message or it throws a
|
||||
Tcl error with a system message. The arguments are:
|
||||
<ul>
|
||||
<li>
|
||||
<b>-force</b>causes the checkpoint to occur regardless of inactivity
|
||||
|
||||
<li>
|
||||
<b>-kbyte</b>causes the checkpoint to occur only if <b><i>kb</i></b> kilobytes
|
||||
of log data has been written since the last checkpoint
|
||||
|
||||
<li>
|
||||
<b>-min</b> causes the checkpoint to occur only if <b><i>min</i></b> minutes
|
||||
have passed since the last checkpoint
|
||||
</ul>
|
||||
|
||||
<hr WIDTH="100%">
|
||||
<br><b>> <env> txn_stat</b>
|
||||
<p>This command returns transaction statistics. It is a direct translation
|
||||
of the <a href="../../docs/api_c/txn_stat.html">txn_stat</a> function.
|
||||
It will return a list of name/value pairs that correspond to the DB_TXN_STAT
|
||||
structure.
|
||||
<hr WIDTH="100%">
|
||||
<br><b>> <env> txn_id_set </b><i> current max</i>
|
||||
<p>This is a diagnosic command that sets the next transaction id to be
|
||||
allocated and the maximum transaction
|
||||
<br>id, which is the point at which the relcaimation algorthm is triggered.
|
||||
<hr WIDTH="100%">
|
||||
<br><b>> <txn> id</b>
|
||||
<p>This command returns the transaction id. It is a direct call to
|
||||
the <a href="../../docs/api_c/txn_id.html">txn_id</a> function. The
|
||||
typical use of this identifier is as the <b><i>locker</i></b> value for
|
||||
the <a href="lock.html">lock_get</a> and <a href="lock.html">lock_vec</a>
|
||||
calls.
|
||||
<hr WIDTH="100%">
|
||||
<br><b>> <txn> prepare</b>
|
||||
<p>This command initiates a two-phase commit. It is a direct call
|
||||
to the <a href="../../docs/api_c/txn_prepare.html">txn_prepare</a> function.
|
||||
It returns either a 0 (for success), a DB error message or it throws a
|
||||
Tcl error with a system message.
|
||||
<hr WIDTH="100%"><a NAME="> <env> lock_vec"></a><b>> <env> txn_timeout
|
||||
<i>timeout</i></b>
|
||||
<p>This command sets thetransaction timeout for transactions started in
|
||||
the future in this environment. The timeout is in micorseconds.
|
||||
<br>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
738
tcl/tcl_compat.c
Normal file
738
tcl/tcl_compat.c
Normal file
@@ -0,0 +1,738 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1999,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: tcl_compat.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
#ifdef CONFIG_TEST
|
||||
|
||||
#define DB_DBM_HSEARCH 1
|
||||
#include "db_int.h"
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#include <tcl.h>
|
||||
#endif
|
||||
#include "dbinc/tcl_db.h"
|
||||
|
||||
/*
|
||||
* bdb_HCommand --
|
||||
* Implements h* functions.
|
||||
*
|
||||
* PUBLIC: int bdb_HCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
|
||||
*/
|
||||
int
|
||||
bdb_HCommand(interp, objc, objv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
{
|
||||
static const char *hcmds[] = {
|
||||
"hcreate",
|
||||
"hdestroy",
|
||||
"hsearch",
|
||||
NULL
|
||||
};
|
||||
enum hcmds {
|
||||
HHCREATE,
|
||||
HHDESTROY,
|
||||
HHSEARCH
|
||||
};
|
||||
static const char *srchacts[] = {
|
||||
"enter",
|
||||
"find",
|
||||
NULL
|
||||
};
|
||||
enum srchacts {
|
||||
ACT_ENTER,
|
||||
ACT_FIND
|
||||
};
|
||||
ENTRY item, *hres;
|
||||
ACTION action;
|
||||
int actindex, cmdindex, nelem, result, ret;
|
||||
Tcl_Obj *res;
|
||||
|
||||
result = TCL_OK;
|
||||
/*
|
||||
* Get the command name index from the object based on the cmds
|
||||
* defined above. This SHOULD NOT fail because we already checked
|
||||
* in the 'berkdb' command.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp,
|
||||
objv[1], hcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
|
||||
return (IS_HELP(objv[1]));
|
||||
|
||||
res = NULL;
|
||||
switch ((enum hcmds)cmdindex) {
|
||||
case HHCREATE:
|
||||
/*
|
||||
* Must be 1 arg, nelem. Error if not.
|
||||
*/
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "nelem");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
result = Tcl_GetIntFromObj(interp, objv[2], &nelem);
|
||||
if (result == TCL_OK) {
|
||||
_debug_check();
|
||||
ret = hcreate((size_t)nelem) == 0 ? 1: 0;
|
||||
(void)_ReturnSetup(
|
||||
interp, ret, DB_RETOK_STD(ret), "hcreate");
|
||||
}
|
||||
break;
|
||||
case HHSEARCH:
|
||||
/*
|
||||
* 3 args for this. Error if different.
|
||||
*/
|
||||
if (objc != 5) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "key data action");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
item.key = Tcl_GetStringFromObj(objv[2], NULL);
|
||||
item.data = Tcl_GetStringFromObj(objv[3], NULL);
|
||||
if (Tcl_GetIndexFromObj(interp, objv[4], srchacts,
|
||||
"action", TCL_EXACT, &actindex) != TCL_OK)
|
||||
return (IS_HELP(objv[4]));
|
||||
switch ((enum srchacts)actindex) {
|
||||
case ACT_ENTER:
|
||||
action = ENTER;
|
||||
break;
|
||||
default:
|
||||
case ACT_FIND:
|
||||
action = FIND;
|
||||
break;
|
||||
}
|
||||
_debug_check();
|
||||
hres = hsearch(item, action);
|
||||
if (hres == NULL)
|
||||
Tcl_SetResult(interp, "-1", TCL_STATIC);
|
||||
else if (action == FIND)
|
||||
Tcl_SetResult(interp, (char *)hres->data, TCL_STATIC);
|
||||
else
|
||||
/* action is ENTER */
|
||||
Tcl_SetResult(interp, "0", TCL_STATIC);
|
||||
|
||||
break;
|
||||
case HHDESTROY:
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
hdestroy();
|
||||
res = Tcl_NewIntObj(0);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Only set result if we have a res. Otherwise, lower
|
||||
* functions have already done so.
|
||||
*/
|
||||
if (result == TCL_OK && res)
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* bdb_NdbmOpen --
|
||||
* Opens an ndbm database.
|
||||
*
|
||||
* PUBLIC: #if DB_DBM_HSEARCH != 0
|
||||
* PUBLIC: int bdb_NdbmOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBM **));
|
||||
* PUBLIC: #endif
|
||||
*/
|
||||
int
|
||||
bdb_NdbmOpen(interp, objc, objv, dbpp)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DBM **dbpp; /* Dbm pointer */
|
||||
{
|
||||
static const char *ndbopen[] = {
|
||||
"-create",
|
||||
"-mode",
|
||||
"-rdonly",
|
||||
"-truncate",
|
||||
"--",
|
||||
NULL
|
||||
};
|
||||
enum ndbopen {
|
||||
NDB_CREATE,
|
||||
NDB_MODE,
|
||||
NDB_RDONLY,
|
||||
NDB_TRUNC,
|
||||
NDB_ENDARG
|
||||
};
|
||||
|
||||
int endarg, i, mode, open_flags, optindex, read_only, result, ret;
|
||||
char *arg, *db;
|
||||
|
||||
result = TCL_OK;
|
||||
endarg = mode = open_flags = read_only = 0;
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?args?");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the option name index from the object based on the args
|
||||
* defined above.
|
||||
*/
|
||||
i = 2;
|
||||
while (i < objc) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i], ndbopen, "option",
|
||||
TCL_EXACT, &optindex) != TCL_OK) {
|
||||
arg = Tcl_GetStringFromObj(objv[i], NULL);
|
||||
if (arg[0] == '-') {
|
||||
result = IS_HELP(objv[i]);
|
||||
goto error;
|
||||
} else
|
||||
Tcl_ResetResult(interp);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
switch ((enum ndbopen)optindex) {
|
||||
case NDB_CREATE:
|
||||
open_flags |= O_CREAT;
|
||||
break;
|
||||
case NDB_RDONLY:
|
||||
read_only = 1;
|
||||
break;
|
||||
case NDB_TRUNC:
|
||||
open_flags |= O_TRUNC;
|
||||
break;
|
||||
case NDB_MODE:
|
||||
if (i >= objc) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"?-mode mode?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Don't need to check result here because
|
||||
* if TCL_ERROR, the error message is already
|
||||
* set up, and we'll bail out below. If ok,
|
||||
* the mode is set and we go on.
|
||||
*/
|
||||
result = Tcl_GetIntFromObj(interp, objv[i++], &mode);
|
||||
break;
|
||||
case NDB_ENDARG:
|
||||
endarg = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If, at any time, parsing the args we get an error,
|
||||
* bail out and return.
|
||||
*/
|
||||
if (result != TCL_OK)
|
||||
goto error;
|
||||
if (endarg)
|
||||
break;
|
||||
}
|
||||
if (result != TCL_OK)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Any args we have left, (better be 0, or 1 left) is a
|
||||
* file name. If we have 0, then an in-memory db. If
|
||||
* there is 1, a db name.
|
||||
*/
|
||||
db = NULL;
|
||||
if (i != objc && i != objc - 1) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?args? ?file?");
|
||||
result = TCL_ERROR;
|
||||
goto error;
|
||||
}
|
||||
if (i != objc)
|
||||
db = Tcl_GetStringFromObj(objv[objc - 1], NULL);
|
||||
|
||||
/*
|
||||
* When we get here, we have already parsed all of our args
|
||||
* and made all our calls to set up the database. Everything
|
||||
* is okay so far, no errors, if we get here.
|
||||
*
|
||||
* Now open the database.
|
||||
*/
|
||||
if (read_only)
|
||||
open_flags |= O_RDONLY;
|
||||
else
|
||||
open_flags |= O_RDWR;
|
||||
_debug_check();
|
||||
if ((*dbpp = dbm_open(db, open_flags, mode)) == NULL) {
|
||||
ret = Tcl_GetErrno();
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"db open");
|
||||
goto error;
|
||||
}
|
||||
return (TCL_OK);
|
||||
|
||||
error:
|
||||
*dbpp = NULL;
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* bdb_DbmCommand --
|
||||
* Implements "dbm" commands.
|
||||
*
|
||||
* PUBLIC: #if DB_DBM_HSEARCH != 0
|
||||
* PUBLIC: int bdb_DbmCommand
|
||||
* PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST*, int, DBM *));
|
||||
* PUBLIC: #endif
|
||||
*/
|
||||
int
|
||||
bdb_DbmCommand(interp, objc, objv, flag, dbm)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
int flag; /* Which db interface */
|
||||
DBM *dbm; /* DBM pointer */
|
||||
{
|
||||
static const char *dbmcmds[] = {
|
||||
"dbmclose",
|
||||
"dbminit",
|
||||
"delete",
|
||||
"fetch",
|
||||
"firstkey",
|
||||
"nextkey",
|
||||
"store",
|
||||
NULL
|
||||
};
|
||||
enum dbmcmds {
|
||||
DBMCLOSE,
|
||||
DBMINIT,
|
||||
DBMDELETE,
|
||||
DBMFETCH,
|
||||
DBMFIRST,
|
||||
DBMNEXT,
|
||||
DBMSTORE
|
||||
};
|
||||
static const char *stflag[] = {
|
||||
"insert", "replace",
|
||||
NULL
|
||||
};
|
||||
enum stflag {
|
||||
STINSERT, STREPLACE
|
||||
};
|
||||
datum key, data;
|
||||
void *dtmp, *ktmp;
|
||||
u_int32_t size;
|
||||
int cmdindex, freedata, freekey, stindex, result, ret;
|
||||
char *name, *t;
|
||||
|
||||
result = TCL_OK;
|
||||
freekey = freedata = 0;
|
||||
dtmp = ktmp = NULL;
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the cmds
|
||||
* defined above. This SHOULD NOT fail because we already checked
|
||||
* in the 'berkdb' command.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp,
|
||||
objv[1], dbmcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
|
||||
return (IS_HELP(objv[1]));
|
||||
|
||||
switch ((enum dbmcmds)cmdindex) {
|
||||
case DBMCLOSE:
|
||||
/*
|
||||
* No arg for this. Error if different.
|
||||
*/
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
if (flag == DBTCL_DBM)
|
||||
ret = dbmclose();
|
||||
else {
|
||||
Tcl_SetResult(interp,
|
||||
"Bad interface flag for command", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
(void)_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "dbmclose");
|
||||
break;
|
||||
case DBMINIT:
|
||||
/*
|
||||
* Must be 1 arg - file.
|
||||
*/
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "file");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
name = Tcl_GetStringFromObj(objv[2], NULL);
|
||||
if (flag == DBTCL_DBM)
|
||||
ret = dbminit(name);
|
||||
else {
|
||||
Tcl_SetResult(interp, "Bad interface flag for command",
|
||||
TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
(void)_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "dbminit");
|
||||
break;
|
||||
case DBMFETCH:
|
||||
/*
|
||||
* 1 arg for this. Error if different.
|
||||
*/
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "key");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if ((ret = _CopyObjBytes(
|
||||
interp, objv[2], &ktmp, &size, &freekey)) != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "dbm fetch");
|
||||
goto out;
|
||||
}
|
||||
key.dsize = (int)size;
|
||||
key.dptr = (char *)ktmp;
|
||||
_debug_check();
|
||||
if (flag == DBTCL_DBM)
|
||||
data = fetch(key);
|
||||
else if (flag == DBTCL_NDBM)
|
||||
data = dbm_fetch(dbm, key);
|
||||
else {
|
||||
Tcl_SetResult(interp,
|
||||
"Bad interface flag for command", TCL_STATIC);
|
||||
result = TCL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
if (data.dptr == NULL ||
|
||||
(ret = __os_malloc(NULL, (size_t)data.dsize + 1, &t)) != 0)
|
||||
Tcl_SetResult(interp, "-1", TCL_STATIC);
|
||||
else {
|
||||
memcpy(t, data.dptr, (size_t)data.dsize);
|
||||
t[data.dsize] = '\0';
|
||||
Tcl_SetResult(interp, t, TCL_VOLATILE);
|
||||
__os_free(NULL, t);
|
||||
}
|
||||
break;
|
||||
case DBMSTORE:
|
||||
/*
|
||||
* 2 args for this. Error if different.
|
||||
*/
|
||||
if (objc != 4 && flag == DBTCL_DBM) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "key data");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (objc != 5 && flag == DBTCL_NDBM) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "key data action");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if ((ret = _CopyObjBytes(
|
||||
interp, objv[2], &ktmp, &size, &freekey)) != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "dbm fetch");
|
||||
goto out;
|
||||
}
|
||||
key.dsize = (int)size;
|
||||
key.dptr = (char *)ktmp;
|
||||
if ((ret = _CopyObjBytes(
|
||||
interp, objv[3], &dtmp, &size, &freedata)) != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "dbm fetch");
|
||||
goto out;
|
||||
}
|
||||
data.dsize = (int)size;
|
||||
data.dptr = (char *)dtmp;
|
||||
_debug_check();
|
||||
if (flag == DBTCL_DBM)
|
||||
ret = store(key, data);
|
||||
else if (flag == DBTCL_NDBM) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[4], stflag,
|
||||
"flag", TCL_EXACT, &stindex) != TCL_OK)
|
||||
return (IS_HELP(objv[4]));
|
||||
switch ((enum stflag)stindex) {
|
||||
case STINSERT:
|
||||
flag = DBM_INSERT;
|
||||
break;
|
||||
case STREPLACE:
|
||||
flag = DBM_REPLACE;
|
||||
break;
|
||||
}
|
||||
ret = dbm_store(dbm, key, data, flag);
|
||||
} else {
|
||||
Tcl_SetResult(interp,
|
||||
"Bad interface flag for command", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
(void)_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "store");
|
||||
break;
|
||||
case DBMDELETE:
|
||||
/*
|
||||
* 1 arg for this. Error if different.
|
||||
*/
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "key");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if ((ret = _CopyObjBytes(
|
||||
interp, objv[2], &ktmp, &size, &freekey)) != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "dbm fetch");
|
||||
goto out;
|
||||
}
|
||||
key.dsize = (int)size;
|
||||
key.dptr = (char *)ktmp;
|
||||
_debug_check();
|
||||
if (flag == DBTCL_DBM)
|
||||
ret = delete(key);
|
||||
else if (flag == DBTCL_NDBM)
|
||||
ret = dbm_delete(dbm, key);
|
||||
else {
|
||||
Tcl_SetResult(interp,
|
||||
"Bad interface flag for command", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
(void)_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "delete");
|
||||
break;
|
||||
case DBMFIRST:
|
||||
/*
|
||||
* No arg for this. Error if different.
|
||||
*/
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
if (flag == DBTCL_DBM)
|
||||
key = firstkey();
|
||||
else if (flag == DBTCL_NDBM)
|
||||
key = dbm_firstkey(dbm);
|
||||
else {
|
||||
Tcl_SetResult(interp,
|
||||
"Bad interface flag for command", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (key.dptr == NULL ||
|
||||
(ret = __os_malloc(NULL, (size_t)key.dsize + 1, &t)) != 0)
|
||||
Tcl_SetResult(interp, "-1", TCL_STATIC);
|
||||
else {
|
||||
memcpy(t, key.dptr, (size_t)key.dsize);
|
||||
t[key.dsize] = '\0';
|
||||
Tcl_SetResult(interp, t, TCL_VOLATILE);
|
||||
__os_free(NULL, t);
|
||||
}
|
||||
break;
|
||||
case DBMNEXT:
|
||||
/*
|
||||
* 0 or 1 arg for this. Error if different.
|
||||
*/
|
||||
_debug_check();
|
||||
if (flag == DBTCL_DBM) {
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if ((ret = _CopyObjBytes(
|
||||
interp, objv[2], &ktmp, &size, &freekey)) != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "dbm fetch");
|
||||
goto out;
|
||||
}
|
||||
key.dsize = (int)size;
|
||||
key.dptr = (char *)ktmp;
|
||||
data = nextkey(key);
|
||||
} else if (flag == DBTCL_NDBM) {
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
data = dbm_nextkey(dbm);
|
||||
} else {
|
||||
Tcl_SetResult(interp,
|
||||
"Bad interface flag for command", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (data.dptr == NULL ||
|
||||
(ret = __os_malloc(NULL, (size_t)data.dsize + 1, &t)) != 0)
|
||||
Tcl_SetResult(interp, "-1", TCL_STATIC);
|
||||
else {
|
||||
memcpy(t, data.dptr, (size_t)data.dsize);
|
||||
t[data.dsize] = '\0';
|
||||
Tcl_SetResult(interp, t, TCL_VOLATILE);
|
||||
__os_free(NULL, t);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
out: if (dtmp != NULL && freedata)
|
||||
__os_free(NULL, dtmp);
|
||||
if (ktmp != NULL && freekey)
|
||||
__os_free(NULL, ktmp);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* ndbm_Cmd --
|
||||
* Implements the "ndbm" widget.
|
||||
*
|
||||
* PUBLIC: int ndbm_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
|
||||
*/
|
||||
int
|
||||
ndbm_Cmd(clientData, interp, objc, objv)
|
||||
ClientData clientData; /* DB handle */
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
{
|
||||
static const char *ndbcmds[] = {
|
||||
"clearerr",
|
||||
"close",
|
||||
"delete",
|
||||
"dirfno",
|
||||
"error",
|
||||
"fetch",
|
||||
"firstkey",
|
||||
"nextkey",
|
||||
"pagfno",
|
||||
"rdonly",
|
||||
"store",
|
||||
NULL
|
||||
};
|
||||
enum ndbcmds {
|
||||
NDBCLRERR,
|
||||
NDBCLOSE,
|
||||
NDBDELETE,
|
||||
NDBDIRFNO,
|
||||
NDBERR,
|
||||
NDBFETCH,
|
||||
NDBFIRST,
|
||||
NDBNEXT,
|
||||
NDBPAGFNO,
|
||||
NDBRDONLY,
|
||||
NDBSTORE
|
||||
};
|
||||
DBM *dbp;
|
||||
DBTCL_INFO *dbip;
|
||||
Tcl_Obj *res;
|
||||
int cmdindex, result, ret;
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
dbp = (DBM *)clientData;
|
||||
dbip = _PtrToInfo((void *)dbp);
|
||||
result = TCL_OK;
|
||||
if (objc <= 1) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (dbp == NULL) {
|
||||
Tcl_SetResult(interp, "NULL db pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (dbip == NULL) {
|
||||
Tcl_SetResult(interp, "NULL db info pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the dbcmds
|
||||
* defined above.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp,
|
||||
objv[1], ndbcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
|
||||
return (IS_HELP(objv[1]));
|
||||
|
||||
res = NULL;
|
||||
switch ((enum ndbcmds)cmdindex) {
|
||||
case NDBCLOSE:
|
||||
_debug_check();
|
||||
dbm_close(dbp);
|
||||
(void)Tcl_DeleteCommand(interp, dbip->i_name);
|
||||
_DeleteInfo(dbip);
|
||||
res = Tcl_NewIntObj(0);
|
||||
break;
|
||||
case NDBDELETE:
|
||||
case NDBFETCH:
|
||||
case NDBFIRST:
|
||||
case NDBNEXT:
|
||||
case NDBSTORE:
|
||||
result = bdb_DbmCommand(interp, objc, objv, DBTCL_NDBM, dbp);
|
||||
break;
|
||||
case NDBCLRERR:
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc > 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbm_clearerr(dbp);
|
||||
if (ret)
|
||||
(void)_ReturnSetup(
|
||||
interp, ret, DB_RETOK_STD(ret), "clearerr");
|
||||
else
|
||||
res = Tcl_NewIntObj(ret);
|
||||
break;
|
||||
case NDBDIRFNO:
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc > 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbm_dirfno(dbp);
|
||||
res = Tcl_NewIntObj(ret);
|
||||
break;
|
||||
case NDBPAGFNO:
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc > 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbm_pagfno(dbp);
|
||||
res = Tcl_NewIntObj(ret);
|
||||
break;
|
||||
case NDBERR:
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc > 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbm_error(dbp);
|
||||
Tcl_SetErrno(ret);
|
||||
Tcl_SetResult(interp,
|
||||
(char *)Tcl_PosixError(interp), TCL_STATIC);
|
||||
break;
|
||||
case NDBRDONLY:
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc > 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbm_rdonly(dbp);
|
||||
if (ret)
|
||||
(void)_ReturnSetup(
|
||||
interp, ret, DB_RETOK_STD(ret), "rdonly");
|
||||
else
|
||||
res = Tcl_NewIntObj(ret);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only set result if we have a res. Otherwise, lower functions have
|
||||
* already done so.
|
||||
*/
|
||||
if (result == TCL_OK && res)
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
#endif /* CONFIG_TEST */
|
||||
3219
tcl/tcl_db.c
Normal file
3219
tcl/tcl_db.c
Normal file
File diff suppressed because it is too large
Load Diff
3892
tcl/tcl_db_pkg.c
Normal file
3892
tcl/tcl_db_pkg.c
Normal file
File diff suppressed because it is too large
Load Diff
973
tcl/tcl_dbcursor.c
Normal file
973
tcl/tcl_dbcursor.c
Normal file
@@ -0,0 +1,973 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1999,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: tcl_dbcursor.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#include <tcl.h>
|
||||
#endif
|
||||
#include "dbinc/tcl_db.h"
|
||||
|
||||
/*
|
||||
* Prototypes for procedures defined later in this file:
|
||||
*/
|
||||
static int tcl_DbcDup __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *));
|
||||
static int tcl_DbcGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *, int));
|
||||
static int tcl_DbcPut __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *));
|
||||
|
||||
/*
|
||||
* PUBLIC: int dbc_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
|
||||
*
|
||||
* dbc_cmd --
|
||||
* Implements the cursor command.
|
||||
*/
|
||||
int
|
||||
dbc_Cmd(clientData, interp, objc, objv)
|
||||
ClientData clientData; /* Cursor handle */
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
{
|
||||
static const char *dbccmds[] = {
|
||||
#ifdef CONFIG_TEST
|
||||
"pget",
|
||||
#endif
|
||||
"close",
|
||||
"del",
|
||||
"dup",
|
||||
"get",
|
||||
"put",
|
||||
NULL
|
||||
};
|
||||
enum dbccmds {
|
||||
#ifdef CONFIG_TEST
|
||||
DBCPGET,
|
||||
#endif
|
||||
DBCCLOSE,
|
||||
DBCDELETE,
|
||||
DBCDUP,
|
||||
DBCGET,
|
||||
DBCPUT
|
||||
};
|
||||
DBC *dbc;
|
||||
DBTCL_INFO *dbip;
|
||||
int cmdindex, result, ret;
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
dbc = (DBC *)clientData;
|
||||
dbip = _PtrToInfo((void *)dbc);
|
||||
result = TCL_OK;
|
||||
|
||||
if (objc <= 1) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (dbc == NULL) {
|
||||
Tcl_SetResult(interp, "NULL dbc pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (dbip == NULL) {
|
||||
Tcl_SetResult(interp, "NULL dbc info pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the berkdbcmds
|
||||
* defined above.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp, objv[1], dbccmds, "command",
|
||||
TCL_EXACT, &cmdindex) != TCL_OK)
|
||||
return (IS_HELP(objv[1]));
|
||||
switch ((enum dbccmds)cmdindex) {
|
||||
#ifdef CONFIG_TEST
|
||||
case DBCPGET:
|
||||
result = tcl_DbcGet(interp, objc, objv, dbc, 1);
|
||||
break;
|
||||
#endif
|
||||
case DBCCLOSE:
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc > 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbc->close(dbc);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"dbc close");
|
||||
if (result == TCL_OK) {
|
||||
(void)Tcl_DeleteCommand(interp, dbip->i_name);
|
||||
_DeleteInfo(dbip);
|
||||
}
|
||||
break;
|
||||
case DBCDELETE:
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc > 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbc->del(dbc, 0);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_DBCDEL(ret),
|
||||
"dbc delete");
|
||||
break;
|
||||
case DBCDUP:
|
||||
result = tcl_DbcDup(interp, objc, objv, dbc);
|
||||
break;
|
||||
case DBCGET:
|
||||
result = tcl_DbcGet(interp, objc, objv, dbc, 0);
|
||||
break;
|
||||
case DBCPUT:
|
||||
result = tcl_DbcPut(interp, objc, objv, dbc);
|
||||
break;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_DbcPut --
|
||||
*/
|
||||
static int
|
||||
tcl_DbcPut(interp, objc, objv, dbc)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DBC *dbc; /* Cursor pointer */
|
||||
{
|
||||
static const char *dbcutopts[] = {
|
||||
#ifdef CONFIG_TEST
|
||||
"-nodupdata",
|
||||
#endif
|
||||
"-after",
|
||||
"-before",
|
||||
"-current",
|
||||
"-keyfirst",
|
||||
"-keylast",
|
||||
"-partial",
|
||||
NULL
|
||||
};
|
||||
enum dbcutopts {
|
||||
#ifdef CONFIG_TEST
|
||||
DBCPUT_NODUPDATA,
|
||||
#endif
|
||||
DBCPUT_AFTER,
|
||||
DBCPUT_BEFORE,
|
||||
DBCPUT_CURRENT,
|
||||
DBCPUT_KEYFIRST,
|
||||
DBCPUT_KEYLAST,
|
||||
DBCPUT_PART
|
||||
};
|
||||
DB *thisdbp;
|
||||
DBT key, data;
|
||||
DBTCL_INFO *dbcip, *dbip;
|
||||
DBTYPE type;
|
||||
Tcl_Obj **elemv, *res;
|
||||
void *dtmp, *ktmp;
|
||||
db_recno_t recno;
|
||||
u_int32_t flag;
|
||||
int elemc, freekey, freedata, i, optindex, result, ret;
|
||||
|
||||
COMPQUIET(dtmp, NULL);
|
||||
COMPQUIET(ktmp, NULL);
|
||||
|
||||
result = TCL_OK;
|
||||
flag = 0;
|
||||
freekey = freedata = 0;
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-args? ?key?");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the options
|
||||
* defined above.
|
||||
*/
|
||||
i = 2;
|
||||
while (i < (objc - 1)) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i], dbcutopts, "option",
|
||||
TCL_EXACT, &optindex) != TCL_OK) {
|
||||
/*
|
||||
* Reset the result so we don't get
|
||||
* an errant error message if there is another error.
|
||||
*/
|
||||
if (IS_HELP(objv[i]) == TCL_OK) {
|
||||
result = TCL_OK;
|
||||
goto out;
|
||||
}
|
||||
Tcl_ResetResult(interp);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
switch ((enum dbcutopts)optindex) {
|
||||
#ifdef CONFIG_TEST
|
||||
case DBCPUT_NODUPDATA:
|
||||
FLAG_CHECK(flag);
|
||||
flag = DB_NODUPDATA;
|
||||
break;
|
||||
#endif
|
||||
case DBCPUT_AFTER:
|
||||
FLAG_CHECK(flag);
|
||||
flag = DB_AFTER;
|
||||
break;
|
||||
case DBCPUT_BEFORE:
|
||||
FLAG_CHECK(flag);
|
||||
flag = DB_BEFORE;
|
||||
break;
|
||||
case DBCPUT_CURRENT:
|
||||
FLAG_CHECK(flag);
|
||||
flag = DB_CURRENT;
|
||||
break;
|
||||
case DBCPUT_KEYFIRST:
|
||||
FLAG_CHECK(flag);
|
||||
flag = DB_KEYFIRST;
|
||||
break;
|
||||
case DBCPUT_KEYLAST:
|
||||
FLAG_CHECK(flag);
|
||||
flag = DB_KEYLAST;
|
||||
break;
|
||||
case DBCPUT_PART:
|
||||
if (i > (objc - 2)) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"?-partial {offset length}?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Get sublist as {offset length}
|
||||
*/
|
||||
result = Tcl_ListObjGetElements(interp, objv[i++],
|
||||
&elemc, &elemv);
|
||||
if (elemc != 2) {
|
||||
Tcl_SetResult(interp,
|
||||
"List must be {offset length}", TCL_STATIC);
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
data.flags |= DB_DBT_PARTIAL;
|
||||
result = _GetUInt32(interp, elemv[0], &data.doff);
|
||||
if (result != TCL_OK)
|
||||
break;
|
||||
result = _GetUInt32(interp, elemv[1], &data.dlen);
|
||||
/*
|
||||
* NOTE: We don't check result here because all we'd
|
||||
* do is break anyway, and we are doing that. If you
|
||||
* add code here, you WILL need to add the check
|
||||
* for result. (See the check for save.doff, a few
|
||||
* lines above and copy that.)
|
||||
*/
|
||||
}
|
||||
if (result != TCL_OK)
|
||||
break;
|
||||
}
|
||||
if (result != TCL_OK)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* We need to determine if we are a recno database or not. If we are,
|
||||
* then key.data is a recno, not a string.
|
||||
*/
|
||||
dbcip = _PtrToInfo(dbc);
|
||||
if (dbcip == NULL)
|
||||
type = DB_UNKNOWN;
|
||||
else {
|
||||
dbip = dbcip->i_parent;
|
||||
if (dbip == NULL) {
|
||||
Tcl_SetResult(interp, "Cursor without parent database",
|
||||
TCL_STATIC);
|
||||
result = TCL_ERROR;
|
||||
return (result);
|
||||
}
|
||||
thisdbp = dbip->i_dbp;
|
||||
(void)thisdbp->get_type(thisdbp, &type);
|
||||
}
|
||||
/*
|
||||
* When we get here, we better have:
|
||||
* 1 arg if -after, -before or -current
|
||||
* 2 args in all other cases
|
||||
*/
|
||||
if (flag == DB_AFTER || flag == DB_BEFORE || flag == DB_CURRENT) {
|
||||
if (i != (objc - 1)) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"?-args? data");
|
||||
result = TCL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* We want to get the key back, so we need to set
|
||||
* up the location to get it back in.
|
||||
*/
|
||||
if (type == DB_RECNO || type == DB_QUEUE) {
|
||||
recno = 0;
|
||||
key.data = &recno;
|
||||
key.size = sizeof(db_recno_t);
|
||||
}
|
||||
} else {
|
||||
if (i != (objc - 2)) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"?-args? key data");
|
||||
result = TCL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
if (type == DB_RECNO || type == DB_QUEUE) {
|
||||
result = _GetUInt32(interp, objv[objc-2], &recno);
|
||||
if (result == TCL_OK) {
|
||||
key.data = &recno;
|
||||
key.size = sizeof(db_recno_t);
|
||||
} else
|
||||
return (result);
|
||||
} else {
|
||||
ret = _CopyObjBytes(interp, objv[objc-2], &ktmp,
|
||||
&key.size, &freekey);
|
||||
if (ret != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_DBCPUT(ret), "dbc put");
|
||||
return (result);
|
||||
}
|
||||
key.data = ktmp;
|
||||
}
|
||||
}
|
||||
ret = _CopyObjBytes(interp, objv[objc-1], &dtmp,
|
||||
&data.size, &freedata);
|
||||
data.data = dtmp;
|
||||
if (ret != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_DBCPUT(ret), "dbc put");
|
||||
goto out;
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbc->put(dbc, &key, &data, flag);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_DBCPUT(ret),
|
||||
"dbc put");
|
||||
if (ret == 0 &&
|
||||
(flag == DB_AFTER || flag == DB_BEFORE) && type == DB_RECNO) {
|
||||
res = Tcl_NewWideIntObj((Tcl_WideInt)*(db_recno_t *)key.data);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
}
|
||||
out:
|
||||
if (freedata)
|
||||
__os_free(NULL, dtmp);
|
||||
if (freekey)
|
||||
__os_free(NULL, ktmp);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_dbc_get --
|
||||
*/
|
||||
static int
|
||||
tcl_DbcGet(interp, objc, objv, dbc, ispget)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DBC *dbc; /* Cursor pointer */
|
||||
int ispget; /* 1 for pget, 0 for get */
|
||||
{
|
||||
static const char *dbcgetopts[] = {
|
||||
#ifdef CONFIG_TEST
|
||||
"-data_buf_size",
|
||||
"-get_both_range",
|
||||
"-key_buf_size",
|
||||
"-multi",
|
||||
"-multi_key",
|
||||
"-nolease",
|
||||
"-read_committed",
|
||||
"-read_uncommitted",
|
||||
#endif
|
||||
"-current",
|
||||
"-first",
|
||||
"-get_both",
|
||||
"-get_recno",
|
||||
"-join_item",
|
||||
"-last",
|
||||
"-next",
|
||||
"-nextdup",
|
||||
"-nextnodup",
|
||||
"-partial",
|
||||
"-prev",
|
||||
"-prevdup",
|
||||
"-prevnodup",
|
||||
"-rmw",
|
||||
"-set",
|
||||
"-set_range",
|
||||
"-set_recno",
|
||||
NULL
|
||||
};
|
||||
enum dbcgetopts {
|
||||
#ifdef CONFIG_TEST
|
||||
DBCGET_DATA_BUF_SIZE,
|
||||
DBCGET_BOTH_RANGE,
|
||||
DBCGET_KEY_BUF_SIZE,
|
||||
DBCGET_MULTI,
|
||||
DBCGET_MULTI_KEY,
|
||||
DBCGET_NOLEASE,
|
||||
DBCGET_READ_COMMITTED,
|
||||
DBCGET_READ_UNCOMMITTED,
|
||||
#endif
|
||||
DBCGET_CURRENT,
|
||||
DBCGET_FIRST,
|
||||
DBCGET_BOTH,
|
||||
DBCGET_RECNO,
|
||||
DBCGET_JOIN,
|
||||
DBCGET_LAST,
|
||||
DBCGET_NEXT,
|
||||
DBCGET_NEXTDUP,
|
||||
DBCGET_NEXTNODUP,
|
||||
DBCGET_PART,
|
||||
DBCGET_PREV,
|
||||
DBCGET_PREVDUP,
|
||||
DBCGET_PREVNODUP,
|
||||
DBCGET_RMW,
|
||||
DBCGET_SET,
|
||||
DBCGET_SETRANGE,
|
||||
DBCGET_SETRECNO
|
||||
};
|
||||
DB *thisdbp;
|
||||
DBT key, data, pdata;
|
||||
DBTCL_INFO *dbcip, *dbip;
|
||||
DBTYPE ptype, type;
|
||||
Tcl_Obj **elemv, *myobj, *retlist;
|
||||
void *dtmp, *ktmp;
|
||||
db_recno_t precno, recno;
|
||||
u_int32_t flag, op;
|
||||
int elemc, freekey, freedata, i, optindex, result, ret;
|
||||
#ifdef CONFIG_TEST
|
||||
int data_buf_size, key_buf_size;
|
||||
|
||||
data_buf_size = key_buf_size = 0;
|
||||
#endif
|
||||
COMPQUIET(dtmp, NULL);
|
||||
COMPQUIET(ktmp, NULL);
|
||||
|
||||
result = TCL_OK;
|
||||
flag = 0;
|
||||
freekey = freedata = 0;
|
||||
memset(&key, 0, sizeof(key));
|
||||
memset(&data, 0, sizeof(data));
|
||||
memset(&pdata, 0, sizeof(DBT));
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-args? ?key?");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the options
|
||||
* defined above.
|
||||
*/
|
||||
i = 2;
|
||||
while (i < objc) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i], dbcgetopts,
|
||||
"option", TCL_EXACT, &optindex) != TCL_OK) {
|
||||
/*
|
||||
* Reset the result so we don't get
|
||||
* an errant error message if there is another error.
|
||||
*/
|
||||
if (IS_HELP(objv[i]) == TCL_OK) {
|
||||
result = TCL_OK;
|
||||
goto out;
|
||||
}
|
||||
Tcl_ResetResult(interp);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
|
||||
#define FLAG_CHECK2_STDARG \
|
||||
(DB_RMW | DB_MULTIPLE | DB_MULTIPLE_KEY | DB_IGNORE_LEASE | \
|
||||
DB_READ_UNCOMMITTED)
|
||||
|
||||
switch ((enum dbcgetopts)optindex) {
|
||||
#ifdef CONFIG_TEST
|
||||
case DBCGET_DATA_BUF_SIZE:
|
||||
result =
|
||||
Tcl_GetIntFromObj(interp, objv[i], &data_buf_size);
|
||||
if (result != TCL_OK)
|
||||
goto out;
|
||||
i++;
|
||||
break;
|
||||
case DBCGET_BOTH_RANGE:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_GET_BOTH_RANGE;
|
||||
break;
|
||||
case DBCGET_KEY_BUF_SIZE:
|
||||
result =
|
||||
Tcl_GetIntFromObj(interp, objv[i], &key_buf_size);
|
||||
if (result != TCL_OK)
|
||||
goto out;
|
||||
i++;
|
||||
break;
|
||||
case DBCGET_MULTI:
|
||||
flag |= DB_MULTIPLE;
|
||||
result =
|
||||
Tcl_GetIntFromObj(interp, objv[i], &data_buf_size);
|
||||
if (result != TCL_OK)
|
||||
goto out;
|
||||
i++;
|
||||
break;
|
||||
case DBCGET_MULTI_KEY:
|
||||
flag |= DB_MULTIPLE_KEY;
|
||||
result =
|
||||
Tcl_GetIntFromObj(interp, objv[i], &data_buf_size);
|
||||
if (result != TCL_OK)
|
||||
goto out;
|
||||
i++;
|
||||
break;
|
||||
case DBCGET_NOLEASE:
|
||||
flag |= DB_IGNORE_LEASE;
|
||||
break;
|
||||
case DBCGET_READ_COMMITTED:
|
||||
flag |= DB_READ_COMMITTED;
|
||||
break;
|
||||
case DBCGET_READ_UNCOMMITTED:
|
||||
flag |= DB_READ_UNCOMMITTED;
|
||||
break;
|
||||
#endif
|
||||
case DBCGET_RMW:
|
||||
flag |= DB_RMW;
|
||||
break;
|
||||
case DBCGET_CURRENT:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_CURRENT;
|
||||
break;
|
||||
case DBCGET_FIRST:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_FIRST;
|
||||
break;
|
||||
case DBCGET_LAST:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_LAST;
|
||||
break;
|
||||
case DBCGET_NEXT:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_NEXT;
|
||||
break;
|
||||
case DBCGET_PREV:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_PREV;
|
||||
break;
|
||||
case DBCGET_PREVDUP:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_PREV_DUP;
|
||||
break;
|
||||
case DBCGET_PREVNODUP:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_PREV_NODUP;
|
||||
break;
|
||||
case DBCGET_NEXTNODUP:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_NEXT_NODUP;
|
||||
break;
|
||||
case DBCGET_NEXTDUP:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_NEXT_DUP;
|
||||
break;
|
||||
case DBCGET_BOTH:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_GET_BOTH;
|
||||
break;
|
||||
case DBCGET_RECNO:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_GET_RECNO;
|
||||
break;
|
||||
case DBCGET_JOIN:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_JOIN_ITEM;
|
||||
break;
|
||||
case DBCGET_SET:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_SET;
|
||||
break;
|
||||
case DBCGET_SETRANGE:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_SET_RANGE;
|
||||
break;
|
||||
case DBCGET_SETRECNO:
|
||||
FLAG_CHECK2(flag, FLAG_CHECK2_STDARG);
|
||||
flag |= DB_SET_RECNO;
|
||||
break;
|
||||
case DBCGET_PART:
|
||||
if (i == objc) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"?-partial {offset length}?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Get sublist as {offset length}
|
||||
*/
|
||||
result = Tcl_ListObjGetElements(interp, objv[i++],
|
||||
&elemc, &elemv);
|
||||
if (elemc != 2) {
|
||||
Tcl_SetResult(interp,
|
||||
"List must be {offset length}", TCL_STATIC);
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
data.flags |= DB_DBT_PARTIAL;
|
||||
result = _GetUInt32(interp, elemv[0], &data.doff);
|
||||
if (result != TCL_OK)
|
||||
break;
|
||||
result = _GetUInt32(interp, elemv[1], &data.dlen);
|
||||
/*
|
||||
* NOTE: We don't check result here because all we'd
|
||||
* do is break anyway, and we are doing that. If you
|
||||
* add code here, you WILL need to add the check
|
||||
* for result. (See the check for save.doff, a few
|
||||
* lines above and copy that.)
|
||||
*/
|
||||
break;
|
||||
}
|
||||
if (result != TCL_OK)
|
||||
break;
|
||||
}
|
||||
if (result != TCL_OK)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* We need to determine if we are a recno database
|
||||
* or not. If we are, then key.data is a recno, not
|
||||
* a string.
|
||||
*/
|
||||
dbcip = _PtrToInfo(dbc);
|
||||
if (dbcip == NULL) {
|
||||
type = DB_UNKNOWN;
|
||||
ptype = DB_UNKNOWN;
|
||||
} else {
|
||||
dbip = dbcip->i_parent;
|
||||
if (dbip == NULL) {
|
||||
Tcl_SetResult(interp, "Cursor without parent database",
|
||||
TCL_STATIC);
|
||||
result = TCL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
thisdbp = dbip->i_dbp;
|
||||
(void)thisdbp->get_type(thisdbp, &type);
|
||||
if (ispget && thisdbp->s_primary != NULL)
|
||||
(void)thisdbp->
|
||||
s_primary->get_type(thisdbp->s_primary, &ptype);
|
||||
else
|
||||
ptype = DB_UNKNOWN;
|
||||
}
|
||||
/*
|
||||
* When we get here, we better have:
|
||||
* 2 args, key and data if GET_BOTH/GET_BOTH_RANGE was specified.
|
||||
* 1 arg if -set, -set_range or -set_recno
|
||||
* 0 in all other cases.
|
||||
*/
|
||||
op = flag & DB_OPFLAGS_MASK;
|
||||
switch (op) {
|
||||
case DB_GET_BOTH:
|
||||
#ifdef CONFIG_TEST
|
||||
case DB_GET_BOTH_RANGE:
|
||||
#endif
|
||||
if (i != (objc - 2)) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"?-args? -get_both key data");
|
||||
result = TCL_ERROR;
|
||||
goto out;
|
||||
} else {
|
||||
if (type == DB_RECNO || type == DB_QUEUE) {
|
||||
result = _GetUInt32(
|
||||
interp, objv[objc-2], &recno);
|
||||
if (result == TCL_OK) {
|
||||
key.data = &recno;
|
||||
key.size = sizeof(db_recno_t);
|
||||
} else
|
||||
goto out;
|
||||
} else {
|
||||
/*
|
||||
* Some get calls (SET_*) can change the
|
||||
* key pointers. So, we need to store
|
||||
* the allocated key space in a tmp.
|
||||
*/
|
||||
ret = _CopyObjBytes(interp, objv[objc-2],
|
||||
&ktmp, &key.size, &freekey);
|
||||
if (ret != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_DBCGET(ret), "dbc get");
|
||||
return (result);
|
||||
}
|
||||
key.data = ktmp;
|
||||
}
|
||||
if (ptype == DB_RECNO || ptype == DB_QUEUE) {
|
||||
result = _GetUInt32(
|
||||
interp, objv[objc-1], &precno);
|
||||
if (result == TCL_OK) {
|
||||
data.data = &precno;
|
||||
data.size = sizeof(db_recno_t);
|
||||
} else
|
||||
goto out;
|
||||
} else {
|
||||
ret = _CopyObjBytes(interp, objv[objc-1],
|
||||
&dtmp, &data.size, &freedata);
|
||||
if (ret != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_DBCGET(ret), "dbc get");
|
||||
goto out;
|
||||
}
|
||||
data.data = dtmp;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DB_SET:
|
||||
case DB_SET_RANGE:
|
||||
case DB_SET_RECNO:
|
||||
if (i != (objc - 1)) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-args? key");
|
||||
result = TCL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
#ifdef CONFIG_TEST
|
||||
if (data_buf_size != 0) {
|
||||
(void)__os_malloc(
|
||||
NULL, (size_t)data_buf_size, &data.data);
|
||||
data.ulen = (u_int32_t)data_buf_size;
|
||||
data.flags |= DB_DBT_USERMEM;
|
||||
} else
|
||||
#endif
|
||||
data.flags |= DB_DBT_MALLOC;
|
||||
if (op == DB_SET_RECNO ||
|
||||
type == DB_RECNO || type == DB_QUEUE) {
|
||||
result = _GetUInt32(interp, objv[objc - 1], &recno);
|
||||
key.data = &recno;
|
||||
key.size = sizeof(db_recno_t);
|
||||
} else {
|
||||
/*
|
||||
* Some get calls (SET_*) can change the
|
||||
* key pointers. So, we need to store
|
||||
* the allocated key space in a tmp.
|
||||
*/
|
||||
ret = _CopyObjBytes(interp, objv[objc-1],
|
||||
&ktmp, &key.size, &freekey);
|
||||
if (ret != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_DBCGET(ret), "dbc get");
|
||||
return (result);
|
||||
}
|
||||
key.data = ktmp;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (i != objc) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-args?");
|
||||
result = TCL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
#ifdef CONFIG_TEST
|
||||
if (key_buf_size != 0) {
|
||||
(void)__os_malloc(
|
||||
NULL, (size_t)key_buf_size, &key.data);
|
||||
key.ulen = (u_int32_t)key_buf_size;
|
||||
key.flags |= DB_DBT_USERMEM;
|
||||
} else
|
||||
#endif
|
||||
key.flags |= DB_DBT_MALLOC;
|
||||
#ifdef CONFIG_TEST
|
||||
if (data_buf_size != 0) {
|
||||
(void)__os_malloc(
|
||||
NULL, (size_t)data_buf_size, &data.data);
|
||||
data.ulen = (u_int32_t)data_buf_size;
|
||||
data.flags |= DB_DBT_USERMEM;
|
||||
} else
|
||||
#endif
|
||||
data.flags |= DB_DBT_MALLOC;
|
||||
}
|
||||
|
||||
_debug_check();
|
||||
if (ispget) {
|
||||
F_SET(&pdata, DB_DBT_MALLOC);
|
||||
ret = dbc->pget(dbc, &key, &data, &pdata, flag);
|
||||
} else
|
||||
ret = dbc->get(dbc, &key, &data, flag);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_DBCGET(ret), "dbc get");
|
||||
if (result == TCL_ERROR)
|
||||
goto out;
|
||||
|
||||
retlist = Tcl_NewListObj(0, NULL);
|
||||
if (ret != 0)
|
||||
goto out1;
|
||||
if (op == DB_GET_RECNO) {
|
||||
recno = *((db_recno_t *)data.data);
|
||||
myobj = Tcl_NewWideIntObj((Tcl_WideInt)recno);
|
||||
result = Tcl_ListObjAppendElement(interp, retlist, myobj);
|
||||
} else {
|
||||
if (flag & (DB_MULTIPLE|DB_MULTIPLE_KEY))
|
||||
result = _SetMultiList(interp,
|
||||
retlist, &key, &data, type, flag);
|
||||
else if ((type == DB_RECNO || type == DB_QUEUE) &&
|
||||
key.data != NULL) {
|
||||
if (ispget)
|
||||
result = _Set3DBTList(interp, retlist, &key, 1,
|
||||
&data,
|
||||
(ptype == DB_RECNO || ptype == DB_QUEUE),
|
||||
&pdata);
|
||||
else
|
||||
result = _SetListRecnoElem(interp, retlist,
|
||||
*(db_recno_t *)key.data,
|
||||
data.data, data.size);
|
||||
} else {
|
||||
if (ispget)
|
||||
result = _Set3DBTList(interp, retlist, &key, 0,
|
||||
&data,
|
||||
(ptype == DB_RECNO || ptype == DB_QUEUE),
|
||||
&pdata);
|
||||
else
|
||||
result = _SetListElem(interp, retlist,
|
||||
key.data, key.size, data.data, data.size);
|
||||
}
|
||||
}
|
||||
out1:
|
||||
if (result == TCL_OK)
|
||||
Tcl_SetObjResult(interp, retlist);
|
||||
/*
|
||||
* If DB_DBT_MALLOC is set we need to free if DB allocated anything.
|
||||
* If DB_DBT_USERMEM is set we need to free it because
|
||||
* we allocated it (for data_buf_size/key_buf_size). That
|
||||
* allocation does not apply to the pdata DBT.
|
||||
*/
|
||||
out:
|
||||
if (key.data != NULL && F_ISSET(&key, DB_DBT_MALLOC))
|
||||
__os_ufree(dbc->env, key.data);
|
||||
if (key.data != NULL && F_ISSET(&key, DB_DBT_USERMEM))
|
||||
__os_free(dbc->env, key.data);
|
||||
if (data.data != NULL && F_ISSET(&data, DB_DBT_MALLOC))
|
||||
__os_ufree(dbc->env, data.data);
|
||||
if (data.data != NULL && F_ISSET(&data, DB_DBT_USERMEM))
|
||||
__os_free(dbc->env, data.data);
|
||||
if (pdata.data != NULL && F_ISSET(&pdata, DB_DBT_MALLOC))
|
||||
__os_ufree(dbc->env, pdata.data);
|
||||
if (freedata)
|
||||
__os_free(NULL, dtmp);
|
||||
if (freekey)
|
||||
__os_free(NULL, ktmp);
|
||||
return (result);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_DbcDup --
|
||||
*/
|
||||
static int
|
||||
tcl_DbcDup(interp, objc, objv, dbc)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DBC *dbc; /* Cursor pointer */
|
||||
{
|
||||
static const char *dbcdupopts[] = {
|
||||
"-position",
|
||||
NULL
|
||||
};
|
||||
enum dbcdupopts {
|
||||
DBCDUP_POS
|
||||
};
|
||||
DBC *newdbc;
|
||||
DBTCL_INFO *dbcip, *newdbcip, *dbip;
|
||||
Tcl_Obj *res;
|
||||
u_int32_t flag;
|
||||
int i, optindex, result, ret;
|
||||
char newname[MSG_SIZE];
|
||||
|
||||
result = TCL_OK;
|
||||
flag = 0;
|
||||
res = NULL;
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-args?");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the options
|
||||
* defined above.
|
||||
*/
|
||||
i = 2;
|
||||
while (i < objc) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i], dbcdupopts,
|
||||
"option", TCL_EXACT, &optindex) != TCL_OK) {
|
||||
/*
|
||||
* Reset the result so we don't get
|
||||
* an errant error message if there is another error.
|
||||
*/
|
||||
if (IS_HELP(objv[i]) == TCL_OK) {
|
||||
result = TCL_OK;
|
||||
goto out;
|
||||
}
|
||||
Tcl_ResetResult(interp);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
switch ((enum dbcdupopts)optindex) {
|
||||
case DBCDUP_POS:
|
||||
flag = DB_POSITION;
|
||||
break;
|
||||
}
|
||||
if (result != TCL_OK)
|
||||
break;
|
||||
}
|
||||
if (result != TCL_OK)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* We need to determine if we are a recno database
|
||||
* or not. If we are, then key.data is a recno, not
|
||||
* a string.
|
||||
*/
|
||||
dbcip = _PtrToInfo(dbc);
|
||||
if (dbcip == NULL) {
|
||||
Tcl_SetResult(interp, "Cursor without info structure",
|
||||
TCL_STATIC);
|
||||
result = TCL_ERROR;
|
||||
goto out;
|
||||
} else {
|
||||
dbip = dbcip->i_parent;
|
||||
if (dbip == NULL) {
|
||||
Tcl_SetResult(interp, "Cursor without parent database",
|
||||
TCL_STATIC);
|
||||
result = TCL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Now duplicate the cursor. If successful, we need to create
|
||||
* a new cursor command.
|
||||
*/
|
||||
snprintf(newname, sizeof(newname),
|
||||
"%s.c%d", dbip->i_name, dbip->i_dbdbcid);
|
||||
newdbcip = _NewInfo(interp, NULL, newname, I_DBC);
|
||||
if (newdbcip != NULL) {
|
||||
ret = dbc->dup(dbc, &newdbc, flag);
|
||||
if (ret == 0) {
|
||||
dbip->i_dbdbcid++;
|
||||
newdbcip->i_parent = dbip;
|
||||
(void)Tcl_CreateObjCommand(interp, newname,
|
||||
(Tcl_ObjCmdProc *)dbc_Cmd,
|
||||
(ClientData)newdbc, NULL);
|
||||
res = NewStringObj(newname, strlen(newname));
|
||||
_SetInfoData(newdbcip, newdbc);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
} else {
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"db dup");
|
||||
_DeleteInfo(newdbcip);
|
||||
}
|
||||
} else {
|
||||
Tcl_SetResult(interp, "Could not set up info", TCL_STATIC);
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
out:
|
||||
return (result);
|
||||
|
||||
}
|
||||
2581
tcl/tcl_env.c
Normal file
2581
tcl/tcl_env.c
Normal file
File diff suppressed because it is too large
Load Diff
814
tcl/tcl_internal.c
Normal file
814
tcl/tcl_internal.c
Normal file
@@ -0,0 +1,814 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1999,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: tcl_internal.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#include <tcl.h>
|
||||
#endif
|
||||
#include "dbinc/tcl_db.h"
|
||||
#include "dbinc/db_page.h"
|
||||
#include "dbinc/db_am.h"
|
||||
|
||||
/*
|
||||
*
|
||||
* internal.c --
|
||||
*
|
||||
* This file contains internal functions we need to maintain
|
||||
* state for our Tcl interface.
|
||||
*
|
||||
* NOTE: This all uses a linear linked list. If we end up with
|
||||
* too many info structs such that this is a performance hit, it
|
||||
* should be redone using hashes or a list per type. The assumption
|
||||
* is that the user won't have more than a few dozen info structs
|
||||
* in operation at any given point in time. Even a complicated
|
||||
* application with a few environments, nested transactions, locking,
|
||||
* and several databases open, using cursors should not have a
|
||||
* negative performance impact, in terms of searching the list to
|
||||
* get/manipulate the info structure.
|
||||
*/
|
||||
|
||||
#define GLOB_CHAR(c) ((c) == '*' || (c) == '?')
|
||||
|
||||
/*
|
||||
* PUBLIC: DBTCL_INFO *_NewInfo __P((Tcl_Interp *,
|
||||
* PUBLIC: void *, char *, enum INFOTYPE));
|
||||
*
|
||||
* _NewInfo --
|
||||
*
|
||||
* This function will create a new info structure and fill it in
|
||||
* with the name and pointer, id and type.
|
||||
*/
|
||||
DBTCL_INFO *
|
||||
_NewInfo(interp, anyp, name, type)
|
||||
Tcl_Interp *interp;
|
||||
void *anyp;
|
||||
char *name;
|
||||
enum INFOTYPE type;
|
||||
{
|
||||
DBTCL_INFO *p;
|
||||
int ret;
|
||||
|
||||
if ((ret = __os_calloc(NULL, sizeof(DBTCL_INFO), 1, &p)) != 0) {
|
||||
Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((ret = __os_strdup(NULL, name, &p->i_name)) != 0) {
|
||||
Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
|
||||
__os_free(NULL, p);
|
||||
return (NULL);
|
||||
}
|
||||
p->i_interp = interp;
|
||||
p->i_anyp = anyp;
|
||||
p->i_type = type;
|
||||
|
||||
LIST_INSERT_HEAD(&__db_infohead, p, entries);
|
||||
return (p);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: void *_NameToPtr __P((CONST char *));
|
||||
*/
|
||||
void *
|
||||
_NameToPtr(name)
|
||||
CONST char *name;
|
||||
{
|
||||
DBTCL_INFO *p;
|
||||
|
||||
LIST_FOREACH(p, &__db_infohead, entries)
|
||||
if (strcmp(name, p->i_name) == 0)
|
||||
return (p->i_anyp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: DBTCL_INFO *_PtrToInfo __P((CONST void *));
|
||||
*/
|
||||
DBTCL_INFO *
|
||||
_PtrToInfo(ptr)
|
||||
CONST void *ptr;
|
||||
{
|
||||
DBTCL_INFO *p;
|
||||
|
||||
LIST_FOREACH(p, &__db_infohead, entries)
|
||||
if (p->i_anyp == ptr)
|
||||
return (p);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: DBTCL_INFO *_NameToInfo __P((CONST char *));
|
||||
*/
|
||||
DBTCL_INFO *
|
||||
_NameToInfo(name)
|
||||
CONST char *name;
|
||||
{
|
||||
DBTCL_INFO *p;
|
||||
|
||||
LIST_FOREACH(p, &__db_infohead, entries)
|
||||
if (strcmp(name, p->i_name) == 0)
|
||||
return (p);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: void _SetInfoData __P((DBTCL_INFO *, void *));
|
||||
*/
|
||||
void
|
||||
_SetInfoData(p, data)
|
||||
DBTCL_INFO *p;
|
||||
void *data;
|
||||
{
|
||||
if (p == NULL)
|
||||
return;
|
||||
p->i_anyp = data;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: void _DeleteInfo __P((DBTCL_INFO *));
|
||||
*/
|
||||
void
|
||||
_DeleteInfo(p)
|
||||
DBTCL_INFO *p;
|
||||
{
|
||||
if (p == NULL)
|
||||
return;
|
||||
LIST_REMOVE(p, entries);
|
||||
if (p->i_lockobj.data != NULL)
|
||||
__os_free(NULL, p->i_lockobj.data);
|
||||
if (p->i_err != NULL && p->i_err != stderr && p->i_err != stdout) {
|
||||
(void)fclose(p->i_err);
|
||||
p->i_err = NULL;
|
||||
}
|
||||
if (p->i_errpfx != NULL)
|
||||
__os_free(NULL, p->i_errpfx);
|
||||
if (p->i_compare != NULL) {
|
||||
Tcl_DecrRefCount(p->i_compare);
|
||||
}
|
||||
if (p->i_dupcompare != NULL) {
|
||||
Tcl_DecrRefCount(p->i_dupcompare);
|
||||
}
|
||||
if (p->i_hashproc != NULL) {
|
||||
Tcl_DecrRefCount(p->i_hashproc);
|
||||
}
|
||||
if (p->i_second_call != NULL) {
|
||||
Tcl_DecrRefCount(p->i_second_call);
|
||||
}
|
||||
if (p->i_rep_eid != NULL) {
|
||||
Tcl_DecrRefCount(p->i_rep_eid);
|
||||
}
|
||||
if (p->i_rep_send != NULL) {
|
||||
Tcl_DecrRefCount(p->i_rep_send);
|
||||
}
|
||||
if (p->i_event != NULL) {
|
||||
Tcl_DecrRefCount(p->i_event);
|
||||
}
|
||||
__os_free(NULL, p->i_name);
|
||||
__os_free(NULL, p);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int _SetListElem __P((Tcl_Interp *,
|
||||
* PUBLIC: Tcl_Obj *, void *, u_int32_t, void *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
_SetListElem(interp, list, elem1, e1cnt, elem2, e2cnt)
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *list;
|
||||
void *elem1, *elem2;
|
||||
u_int32_t e1cnt, e2cnt;
|
||||
{
|
||||
Tcl_Obj *myobjv[2], *thislist;
|
||||
int myobjc;
|
||||
|
||||
myobjc = 2;
|
||||
myobjv[0] = Tcl_NewByteArrayObj((u_char *)elem1, (int)e1cnt);
|
||||
myobjv[1] = Tcl_NewByteArrayObj((u_char *)elem2, (int)e2cnt);
|
||||
thislist = Tcl_NewListObj(myobjc, myobjv);
|
||||
if (thislist == NULL)
|
||||
return (TCL_ERROR);
|
||||
return (Tcl_ListObjAppendElement(interp, list, thislist));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int _SetListElemInt __P((Tcl_Interp *, Tcl_Obj *, void *, long));
|
||||
*/
|
||||
int
|
||||
_SetListElemInt(interp, list, elem1, elem2)
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *list;
|
||||
void *elem1;
|
||||
long elem2;
|
||||
{
|
||||
Tcl_Obj *myobjv[2], *thislist;
|
||||
int myobjc;
|
||||
|
||||
myobjc = 2;
|
||||
myobjv[0] =
|
||||
Tcl_NewByteArrayObj((u_char *)elem1, (int)strlen((char *)elem1));
|
||||
myobjv[1] = Tcl_NewLongObj(elem2);
|
||||
thislist = Tcl_NewListObj(myobjc, myobjv);
|
||||
if (thislist == NULL)
|
||||
return (TCL_ERROR);
|
||||
return (Tcl_ListObjAppendElement(interp, list, thislist));
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't compile this code if we don't have sequences compiled into the DB
|
||||
* library, it's likely because we don't have a 64-bit type, and trying to
|
||||
* use int64_t is going to result in syntax errors.
|
||||
*/
|
||||
#ifdef HAVE_64BIT_TYPES
|
||||
/*
|
||||
* PUBLIC: int _SetListElemWideInt __P((Tcl_Interp *,
|
||||
* PUBLIC: Tcl_Obj *, void *, int64_t));
|
||||
*/
|
||||
int
|
||||
_SetListElemWideInt(interp, list, elem1, elem2)
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *list;
|
||||
void *elem1;
|
||||
int64_t elem2;
|
||||
{
|
||||
Tcl_Obj *myobjv[2], *thislist;
|
||||
int myobjc;
|
||||
|
||||
myobjc = 2;
|
||||
myobjv[0] =
|
||||
Tcl_NewByteArrayObj((u_char *)elem1, (int)strlen((char *)elem1));
|
||||
myobjv[1] = Tcl_NewWideIntObj(elem2);
|
||||
thislist = Tcl_NewListObj(myobjc, myobjv);
|
||||
if (thislist == NULL)
|
||||
return (TCL_ERROR);
|
||||
return (Tcl_ListObjAppendElement(interp, list, thislist));
|
||||
}
|
||||
#endif /* HAVE_64BIT_TYPES */
|
||||
|
||||
/*
|
||||
* PUBLIC: int _SetListRecnoElem __P((Tcl_Interp *, Tcl_Obj *,
|
||||
* PUBLIC: db_recno_t, u_char *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
_SetListRecnoElem(interp, list, elem1, elem2, e2size)
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *list;
|
||||
db_recno_t elem1;
|
||||
u_char *elem2;
|
||||
u_int32_t e2size;
|
||||
{
|
||||
Tcl_Obj *myobjv[2], *thislist;
|
||||
int myobjc;
|
||||
|
||||
myobjc = 2;
|
||||
myobjv[0] = Tcl_NewWideIntObj((Tcl_WideInt)elem1);
|
||||
myobjv[1] = Tcl_NewByteArrayObj(elem2, (int)e2size);
|
||||
thislist = Tcl_NewListObj(myobjc, myobjv);
|
||||
if (thislist == NULL)
|
||||
return (TCL_ERROR);
|
||||
return (Tcl_ListObjAppendElement(interp, list, thislist));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* _Set3DBTList --
|
||||
* This is really analogous to both _SetListElem and
|
||||
* _SetListRecnoElem--it's used for three-DBT lists returned by
|
||||
* DB->pget and DBC->pget(). We'd need a family of four functions
|
||||
* to handle all the recno/non-recno cases, however, so we make
|
||||
* this a little more aware of the internals and do the logic inside.
|
||||
*
|
||||
* XXX
|
||||
* One of these days all these functions should probably be cleaned up
|
||||
* to eliminate redundancy and bring them into the standard DB
|
||||
* function namespace.
|
||||
*
|
||||
* PUBLIC: int _Set3DBTList __P((Tcl_Interp *, Tcl_Obj *, DBT *, int,
|
||||
* PUBLIC: DBT *, int, DBT *));
|
||||
*/
|
||||
int
|
||||
_Set3DBTList(interp, list, elem1, is1recno, elem2, is2recno, elem3)
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *list;
|
||||
DBT *elem1, *elem2, *elem3;
|
||||
int is1recno, is2recno;
|
||||
{
|
||||
|
||||
Tcl_Obj *myobjv[3], *thislist;
|
||||
|
||||
if (is1recno)
|
||||
myobjv[0] = Tcl_NewWideIntObj(
|
||||
(Tcl_WideInt)*(db_recno_t *)elem1->data);
|
||||
else
|
||||
myobjv[0] = Tcl_NewByteArrayObj(
|
||||
(u_char *)elem1->data, (int)elem1->size);
|
||||
|
||||
if (is2recno)
|
||||
myobjv[1] = Tcl_NewWideIntObj(
|
||||
(Tcl_WideInt)*(db_recno_t *)elem2->data);
|
||||
else
|
||||
myobjv[1] = Tcl_NewByteArrayObj(
|
||||
(u_char *)elem2->data, (int)elem2->size);
|
||||
|
||||
myobjv[2] = Tcl_NewByteArrayObj(
|
||||
(u_char *)elem3->data, (int)elem3->size);
|
||||
|
||||
thislist = Tcl_NewListObj(3, myobjv);
|
||||
|
||||
if (thislist == NULL)
|
||||
return (TCL_ERROR);
|
||||
return (Tcl_ListObjAppendElement(interp, list, thislist));
|
||||
}
|
||||
|
||||
/*
|
||||
* _SetMultiList -- build a list for return from multiple get.
|
||||
*
|
||||
* PUBLIC: int _SetMultiList __P((Tcl_Interp *,
|
||||
* PUBLIC: Tcl_Obj *, DBT *, DBT*, DBTYPE, u_int32_t));
|
||||
*/
|
||||
int
|
||||
_SetMultiList(interp, list, key, data, type, flag)
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *list;
|
||||
DBT *key, *data;
|
||||
DBTYPE type;
|
||||
u_int32_t flag;
|
||||
{
|
||||
db_recno_t recno;
|
||||
u_int32_t dlen, klen;
|
||||
int result;
|
||||
void *pointer, *dp, *kp;
|
||||
|
||||
recno = 0;
|
||||
dlen = 0;
|
||||
kp = NULL;
|
||||
|
||||
DB_MULTIPLE_INIT(pointer, data);
|
||||
result = TCL_OK;
|
||||
|
||||
if (type == DB_RECNO || type == DB_QUEUE)
|
||||
recno = *(db_recno_t *) key->data;
|
||||
else
|
||||
kp = key->data;
|
||||
klen = key->size;
|
||||
do {
|
||||
if (flag & DB_MULTIPLE_KEY) {
|
||||
if (type == DB_RECNO || type == DB_QUEUE)
|
||||
DB_MULTIPLE_RECNO_NEXT(pointer,
|
||||
data, recno, dp, dlen);
|
||||
else
|
||||
DB_MULTIPLE_KEY_NEXT(pointer,
|
||||
data, kp, klen, dp, dlen);
|
||||
} else
|
||||
DB_MULTIPLE_NEXT(pointer, data, dp, dlen);
|
||||
|
||||
if (pointer == NULL)
|
||||
break;
|
||||
|
||||
if (type == DB_RECNO || type == DB_QUEUE) {
|
||||
result =
|
||||
_SetListRecnoElem(interp, list, recno, dp, dlen);
|
||||
recno++;
|
||||
/* Wrap around and skip zero. */
|
||||
if (recno == 0)
|
||||
recno++;
|
||||
} else
|
||||
result = _SetListElem(interp, list, kp, klen, dp, dlen);
|
||||
} while (result == TCL_OK);
|
||||
|
||||
return (result);
|
||||
}
|
||||
/*
|
||||
* PUBLIC: int _GetGlobPrefix __P((char *, char **));
|
||||
*/
|
||||
int
|
||||
_GetGlobPrefix(pattern, prefix)
|
||||
char *pattern;
|
||||
char **prefix;
|
||||
{
|
||||
int i, j;
|
||||
char *p;
|
||||
|
||||
/*
|
||||
* Duplicate it, we get enough space and most of the work is done.
|
||||
*/
|
||||
if (__os_strdup(NULL, pattern, prefix) != 0)
|
||||
return (1);
|
||||
|
||||
p = *prefix;
|
||||
for (i = 0, j = 0; p[i] && !GLOB_CHAR(p[i]); i++, j++)
|
||||
/*
|
||||
* Check for an escaped character and adjust
|
||||
*/
|
||||
if (p[i] == '\\' && p[i+1]) {
|
||||
p[j] = p[i+1];
|
||||
i++;
|
||||
} else
|
||||
p[j] = p[i];
|
||||
p[j] = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int _ReturnSetup __P((Tcl_Interp *, int, int, char *));
|
||||
*/
|
||||
int
|
||||
_ReturnSetup(interp, ret, ok, errmsg)
|
||||
Tcl_Interp *interp;
|
||||
int ret, ok;
|
||||
char *errmsg;
|
||||
{
|
||||
char *msg;
|
||||
|
||||
if (ret > 0)
|
||||
return (_ErrorSetup(interp, ret, errmsg));
|
||||
|
||||
/*
|
||||
* We either have success or a DB error. If a DB error, set up the
|
||||
* string. We return an error if not one of the errors we catch.
|
||||
* If anyone wants to reset the result to return anything different,
|
||||
* then the calling function is responsible for doing so via
|
||||
* Tcl_ResetResult or another Tcl_SetObjResult.
|
||||
*/
|
||||
if (ret == 0) {
|
||||
Tcl_SetResult(interp, "0", TCL_STATIC);
|
||||
return (TCL_OK);
|
||||
}
|
||||
|
||||
msg = db_strerror(ret);
|
||||
Tcl_AppendResult(interp, msg, NULL);
|
||||
|
||||
if (ok)
|
||||
return (TCL_OK);
|
||||
else {
|
||||
Tcl_SetErrorCode(interp, "BerkeleyDB", msg, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int _ErrorSetup __P((Tcl_Interp *, int, char *));
|
||||
*/
|
||||
int
|
||||
_ErrorSetup(interp, ret, errmsg)
|
||||
Tcl_Interp *interp;
|
||||
int ret;
|
||||
char *errmsg;
|
||||
{
|
||||
Tcl_SetErrno(ret);
|
||||
Tcl_AppendResult(interp, errmsg, ":", Tcl_PosixError(interp), NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: void _ErrorFunc __P((const DB_ENV *, CONST char *, const char *));
|
||||
*/
|
||||
void
|
||||
_ErrorFunc(dbenv, pfx, msg)
|
||||
const DB_ENV *dbenv;
|
||||
CONST char *pfx;
|
||||
const char *msg;
|
||||
{
|
||||
DBTCL_INFO *p;
|
||||
Tcl_Interp *interp;
|
||||
size_t size;
|
||||
char *err;
|
||||
|
||||
COMPQUIET(dbenv, NULL);
|
||||
|
||||
p = _NameToInfo(pfx);
|
||||
if (p == NULL)
|
||||
return;
|
||||
interp = p->i_interp;
|
||||
|
||||
size = strlen(pfx) + strlen(msg) + 4;
|
||||
/*
|
||||
* If we cannot allocate enough to put together the prefix
|
||||
* and message then give them just the message.
|
||||
*/
|
||||
if (__os_malloc(NULL, size, &err) != 0) {
|
||||
Tcl_AddErrorInfo(interp, msg);
|
||||
Tcl_AppendResult(interp, msg, "\n", NULL);
|
||||
return;
|
||||
}
|
||||
snprintf(err, size, "%s: %s", pfx, msg);
|
||||
Tcl_AddErrorInfo(interp, err);
|
||||
Tcl_AppendResult(interp, err, "\n", NULL);
|
||||
__os_free(NULL, err);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: void _EventFunc __P((DB_ENV *, u_int32_t, void *));
|
||||
*/
|
||||
void
|
||||
_EventFunc(dbenv, event, info)
|
||||
DB_ENV *dbenv;
|
||||
u_int32_t event;
|
||||
void *info;
|
||||
{
|
||||
#define TCLDB_EVENTITEMS 2 /* Event name and any info */
|
||||
#define TCLDB_SENDEVENT 3 /* Event Tcl proc, env name, event objects. */
|
||||
DBTCL_INFO *ip;
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *event_o, *origobj;
|
||||
Tcl_Obj *myobjv[TCLDB_EVENTITEMS], *objv[TCLDB_SENDEVENT];
|
||||
int i, myobjc, result;
|
||||
|
||||
ip = (DBTCL_INFO *)dbenv->app_private;
|
||||
interp = ip->i_interp;
|
||||
if (ip->i_event == NULL)
|
||||
return;
|
||||
objv[0] = ip->i_event;
|
||||
objv[1] = NewStringObj(ip->i_name, strlen(ip->i_name));
|
||||
|
||||
/*
|
||||
* Most events don't have additional info. Assume none
|
||||
* and handle individually those that do.
|
||||
*/
|
||||
myobjv[1] = NULL;
|
||||
myobjc = 1;
|
||||
switch (event) {
|
||||
case DB_EVENT_PANIC:
|
||||
/*
|
||||
* Info is the original error code.
|
||||
*/
|
||||
myobjv[0] = NewStringObj("panic", strlen("panic"));
|
||||
myobjv[myobjc++] = Tcl_NewIntObj(*(int *)info);
|
||||
break;
|
||||
case DB_EVENT_REP_CLIENT:
|
||||
myobjv[0] = NewStringObj("rep_client", strlen("rep_client"));
|
||||
break;
|
||||
case DB_EVENT_REP_ELECTED:
|
||||
myobjv[0] = NewStringObj("elected", strlen("elected"));
|
||||
break;
|
||||
case DB_EVENT_REP_MASTER:
|
||||
myobjv[0] = NewStringObj("rep_master", strlen("rep_master"));
|
||||
break;
|
||||
case DB_EVENT_REP_NEWMASTER:
|
||||
/*
|
||||
* Info is the EID of the new master.
|
||||
*/
|
||||
myobjv[0] = NewStringObj("newmaster", strlen("newmaster"));
|
||||
myobjv[myobjc++] = Tcl_NewIntObj(*(int *)info);
|
||||
break;
|
||||
case DB_EVENT_REP_PERM_FAILED:
|
||||
myobjv[0] = NewStringObj("perm_failed", strlen("perm_failed"));
|
||||
break;
|
||||
case DB_EVENT_REP_STARTUPDONE:
|
||||
myobjv[0] = NewStringObj("startupdone", strlen("startupdone"));
|
||||
break;
|
||||
case DB_EVENT_WRITE_FAILED:
|
||||
myobjv[0] =
|
||||
NewStringObj("write_failed", strlen("write_failed"));
|
||||
break;
|
||||
default:
|
||||
__db_errx(dbenv->env, "Tcl unknown event %lu", (u_long)event);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < myobjc; i++)
|
||||
Tcl_IncrRefCount(myobjv[i]);
|
||||
|
||||
event_o = Tcl_NewListObj(myobjc, myobjv);
|
||||
Tcl_IncrRefCount(event_o);
|
||||
objv[2] = event_o;
|
||||
|
||||
/*
|
||||
* We really want to return the original result to the
|
||||
* user. So, save the result obj here, and then after
|
||||
* we've taken care of the Tcl_EvalObjv, set the result
|
||||
* back to this original result.
|
||||
*/
|
||||
origobj = Tcl_GetObjResult(interp);
|
||||
Tcl_IncrRefCount(origobj);
|
||||
result = Tcl_EvalObjv(interp, TCLDB_SENDEVENT, objv, 0);
|
||||
if (result != TCL_OK) {
|
||||
/*
|
||||
* XXX
|
||||
* This probably isn't the right error behavior, but
|
||||
* this error should only happen if the Tcl callback is
|
||||
* somehow invalid, which is a fatal scripting bug.
|
||||
* The event handler is a void function so we either
|
||||
* just return or abort.
|
||||
* For now, abort.
|
||||
*/
|
||||
__db_errx(dbenv->env, "Tcl event failure");
|
||||
__os_abort(dbenv->env);
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp, origobj);
|
||||
Tcl_DecrRefCount(origobj);
|
||||
for (i = 0; i < myobjc; i++)
|
||||
Tcl_DecrRefCount(myobjv[i]);
|
||||
Tcl_DecrRefCount(event_o);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#define INVALID_LSNMSG "Invalid LSN with %d parts. Should have 2.\n"
|
||||
|
||||
/*
|
||||
* PUBLIC: int _GetLsn __P((Tcl_Interp *, Tcl_Obj *, DB_LSN *));
|
||||
*/
|
||||
int
|
||||
_GetLsn(interp, obj, lsn)
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *obj;
|
||||
DB_LSN *lsn;
|
||||
{
|
||||
Tcl_Obj **myobjv;
|
||||
char msg[MSG_SIZE];
|
||||
int myobjc, result;
|
||||
u_int32_t tmp;
|
||||
|
||||
result = Tcl_ListObjGetElements(interp, obj, &myobjc, &myobjv);
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
if (myobjc != 2) {
|
||||
result = TCL_ERROR;
|
||||
snprintf(msg, MSG_SIZE, INVALID_LSNMSG, myobjc);
|
||||
Tcl_SetResult(interp, msg, TCL_VOLATILE);
|
||||
return (result);
|
||||
}
|
||||
result = _GetUInt32(interp, myobjv[0], &tmp);
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
lsn->file = tmp;
|
||||
result = _GetUInt32(interp, myobjv[1], &tmp);
|
||||
lsn->offset = tmp;
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* _GetUInt32 --
|
||||
* Get a u_int32_t from a Tcl object. Tcl_GetIntFromObj does the
|
||||
* right thing most of the time, but on machines where a long is 8 bytes
|
||||
* and an int is 4 bytes, it errors on integers between the maximum
|
||||
* int32_t and the maximum u_int32_t. This is correct, but we generally
|
||||
* want a u_int32_t in the end anyway, so we use Tcl_GetLongFromObj and do
|
||||
* the bounds checking ourselves.
|
||||
*
|
||||
* This code looks much like Tcl_GetIntFromObj, only with a different
|
||||
* bounds check. It's essentially Tcl_GetUnsignedIntFromObj, which
|
||||
* unfortunately doesn't exist.
|
||||
*
|
||||
* PUBLIC: int _GetUInt32 __P((Tcl_Interp *, Tcl_Obj *, u_int32_t *));
|
||||
*/
|
||||
int
|
||||
_GetUInt32(interp, obj, resp)
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *obj;
|
||||
u_int32_t *resp;
|
||||
{
|
||||
int result;
|
||||
long ltmp;
|
||||
|
||||
result = Tcl_GetLongFromObj(interp, obj, <mp);
|
||||
if (result != TCL_OK)
|
||||
return (result);
|
||||
|
||||
if ((unsigned long)ltmp != (u_int32_t)ltmp) {
|
||||
if (interp != NULL) {
|
||||
Tcl_ResetResult(interp);
|
||||
Tcl_AppendToObj(Tcl_GetObjResult(interp),
|
||||
"integer value too large for u_int32_t", -1);
|
||||
}
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
*resp = (u_int32_t)ltmp;
|
||||
return (TCL_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* _GetFlagsList --
|
||||
* Get a new Tcl object, containing a list of the string values
|
||||
* associated with a particular set of flag values.
|
||||
*
|
||||
* PUBLIC: Tcl_Obj *_GetFlagsList __P((Tcl_Interp *, u_int32_t, const FN *));
|
||||
*/
|
||||
Tcl_Obj *
|
||||
_GetFlagsList(interp, flags, fnp)
|
||||
Tcl_Interp *interp;
|
||||
u_int32_t flags;
|
||||
const FN *fnp;
|
||||
{
|
||||
Tcl_Obj *newlist, *newobj;
|
||||
int result;
|
||||
|
||||
newlist = Tcl_NewObj();
|
||||
|
||||
/*
|
||||
* If the Berkeley DB library wasn't compiled with statistics, then
|
||||
* we may get a NULL reference.
|
||||
*/
|
||||
if (fnp == NULL)
|
||||
return (newlist);
|
||||
|
||||
/*
|
||||
* Append a Tcl_Obj containing each pertinent flag string to the
|
||||
* specified Tcl list.
|
||||
*/
|
||||
for (; fnp->mask != 0; ++fnp)
|
||||
if (LF_ISSET(fnp->mask)) {
|
||||
newobj = NewStringObj(fnp->name, strlen(fnp->name));
|
||||
result =
|
||||
Tcl_ListObjAppendElement(interp, newlist, newobj);
|
||||
|
||||
/*
|
||||
* Tcl_ListObjAppendElement is defined to return TCL_OK
|
||||
* unless newlist isn't actually a list (or convertible
|
||||
* into one). If this is the case, we screwed up badly
|
||||
* somehow.
|
||||
*/
|
||||
DB_ASSERT(NULL, result == TCL_OK);
|
||||
}
|
||||
|
||||
return (newlist);
|
||||
}
|
||||
|
||||
int __debug_stop, __debug_on, __debug_print, __debug_test;
|
||||
|
||||
/*
|
||||
* PUBLIC: void _debug_check __P((void));
|
||||
*/
|
||||
void
|
||||
_debug_check()
|
||||
{
|
||||
if (__debug_on == 0)
|
||||
return;
|
||||
|
||||
if (__debug_print != 0) {
|
||||
printf("\r%7d:", __debug_on);
|
||||
(void)fflush(stdout);
|
||||
}
|
||||
if (__debug_on++ == __debug_test || __debug_stop)
|
||||
__db_loadme();
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Tcl 8.1+ Tcl_GetByteArrayFromObj/Tcl_GetIntFromObj bug.
|
||||
*
|
||||
* There is a bug in Tcl 8.1+ and byte arrays in that if it happens
|
||||
* to use an object as both a byte array and something else like
|
||||
* an int, and you've done a Tcl_GetByteArrayFromObj, then you
|
||||
* do a Tcl_GetIntFromObj, your memory is deleted.
|
||||
*
|
||||
* Workaround is for all byte arrays we want to use, if it can be
|
||||
* represented as an integer, we copy it so that we don't lose the
|
||||
* memory.
|
||||
*/
|
||||
/*
|
||||
* PUBLIC: int _CopyObjBytes __P((Tcl_Interp *, Tcl_Obj *obj, void *,
|
||||
* PUBLIC: u_int32_t *, int *));
|
||||
*/
|
||||
int
|
||||
_CopyObjBytes(interp, obj, newp, sizep, freep)
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *obj;
|
||||
void *newp;
|
||||
u_int32_t *sizep;
|
||||
int *freep;
|
||||
{
|
||||
void *tmp, *new;
|
||||
int i, len, ret;
|
||||
|
||||
/*
|
||||
* If the object is not an int, then just return the byte
|
||||
* array because it won't be transformed out from under us.
|
||||
* If it is a number, we need to copy it.
|
||||
*/
|
||||
*freep = 0;
|
||||
ret = Tcl_GetIntFromObj(interp, obj, &i);
|
||||
tmp = Tcl_GetByteArrayFromObj(obj, &len);
|
||||
*sizep = (u_int32_t)len;
|
||||
if (ret == TCL_ERROR) {
|
||||
Tcl_ResetResult(interp);
|
||||
*(void **)newp = tmp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get here, we have an integer that might be reused
|
||||
* at some other point so we cannot count on GetByteArray
|
||||
* keeping our pointer valid.
|
||||
*/
|
||||
if ((ret = __os_malloc(NULL, (size_t)len, &new)) != 0)
|
||||
return (ret);
|
||||
memcpy(new, tmp, (size_t)len);
|
||||
*(void **)newp = new;
|
||||
*freep = 1;
|
||||
return (0);
|
||||
}
|
||||
775
tcl/tcl_lock.c
Normal file
775
tcl/tcl_lock.c
Normal file
@@ -0,0 +1,775 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1999,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: tcl_lock.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#include <tcl.h>
|
||||
#endif
|
||||
#include "dbinc/tcl_db.h"
|
||||
|
||||
/*
|
||||
* Prototypes for procedures defined later in this file:
|
||||
*/
|
||||
#ifdef CONFIG_TEST
|
||||
static int lock_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
|
||||
static int _LockMode __P((Tcl_Interp *, Tcl_Obj *, db_lockmode_t *));
|
||||
static int _GetThisLock __P((Tcl_Interp *, DB_ENV *, u_int32_t,
|
||||
u_int32_t, DBT *, db_lockmode_t, char *));
|
||||
static void _LockPutInfo __P((Tcl_Interp *, db_lockop_t, DB_LOCK *,
|
||||
u_int32_t, DBT *));
|
||||
|
||||
/*
|
||||
* tcl_LockDetect --
|
||||
*
|
||||
* PUBLIC: int tcl_LockDetect __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_LockDetect(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
static const char *ldopts[] = {
|
||||
"default",
|
||||
"expire",
|
||||
"maxlocks",
|
||||
"maxwrites",
|
||||
"minlocks",
|
||||
"minwrites",
|
||||
"oldest",
|
||||
"random",
|
||||
"youngest",
|
||||
NULL
|
||||
};
|
||||
enum ldopts {
|
||||
LD_DEFAULT,
|
||||
LD_EXPIRE,
|
||||
LD_MAXLOCKS,
|
||||
LD_MAXWRITES,
|
||||
LD_MINLOCKS,
|
||||
LD_MINWRITES,
|
||||
LD_OLDEST,
|
||||
LD_RANDOM,
|
||||
LD_YOUNGEST
|
||||
};
|
||||
u_int32_t flag, policy;
|
||||
int i, optindex, result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
flag = policy = 0;
|
||||
i = 2;
|
||||
while (i < objc) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i],
|
||||
ldopts, "option", TCL_EXACT, &optindex) != TCL_OK)
|
||||
return (IS_HELP(objv[i]));
|
||||
i++;
|
||||
switch ((enum ldopts)optindex) {
|
||||
case LD_DEFAULT:
|
||||
FLAG_CHECK(policy);
|
||||
policy = DB_LOCK_DEFAULT;
|
||||
break;
|
||||
case LD_EXPIRE:
|
||||
FLAG_CHECK(policy);
|
||||
policy = DB_LOCK_EXPIRE;
|
||||
break;
|
||||
case LD_MAXLOCKS:
|
||||
FLAG_CHECK(policy);
|
||||
policy = DB_LOCK_MAXLOCKS;
|
||||
break;
|
||||
case LD_MAXWRITES:
|
||||
FLAG_CHECK(policy);
|
||||
policy = DB_LOCK_MAXWRITE;
|
||||
break;
|
||||
case LD_MINLOCKS:
|
||||
FLAG_CHECK(policy);
|
||||
policy = DB_LOCK_MINLOCKS;
|
||||
break;
|
||||
case LD_MINWRITES:
|
||||
FLAG_CHECK(policy);
|
||||
policy = DB_LOCK_MINWRITE;
|
||||
break;
|
||||
case LD_OLDEST:
|
||||
FLAG_CHECK(policy);
|
||||
policy = DB_LOCK_OLDEST;
|
||||
break;
|
||||
case LD_RANDOM:
|
||||
FLAG_CHECK(policy);
|
||||
policy = DB_LOCK_RANDOM;
|
||||
break;
|
||||
case LD_YOUNGEST:
|
||||
FLAG_CHECK(policy);
|
||||
policy = DB_LOCK_YOUNGEST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_debug_check();
|
||||
ret = dbenv->lock_detect(dbenv, flag, policy, NULL);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock detect");
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_LockGet --
|
||||
*
|
||||
* PUBLIC: int tcl_LockGet __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_LockGet(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
static const char *lgopts[] = {
|
||||
"-nowait",
|
||||
NULL
|
||||
};
|
||||
enum lgopts {
|
||||
LGNOWAIT
|
||||
};
|
||||
DBT obj;
|
||||
Tcl_Obj *res;
|
||||
void *otmp;
|
||||
db_lockmode_t mode;
|
||||
u_int32_t flag, lockid;
|
||||
int freeobj, optindex, result, ret;
|
||||
char newname[MSG_SIZE];
|
||||
|
||||
result = TCL_OK;
|
||||
freeobj = 0;
|
||||
memset(newname, 0, MSG_SIZE);
|
||||
if (objc != 5 && objc != 6) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-nowait? mode id obj");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
/*
|
||||
* Work back from required args.
|
||||
* Last arg is obj.
|
||||
* Second last is lock id.
|
||||
* Third last is lock mode.
|
||||
*/
|
||||
memset(&obj, 0, sizeof(obj));
|
||||
|
||||
if ((result =
|
||||
_GetUInt32(interp, objv[objc-2], &lockid)) != TCL_OK)
|
||||
return (result);
|
||||
|
||||
ret = _CopyObjBytes(interp, objv[objc-1], &otmp,
|
||||
&obj.size, &freeobj);
|
||||
if (ret != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "lock get");
|
||||
return (result);
|
||||
}
|
||||
obj.data = otmp;
|
||||
if ((result = _LockMode(interp, objv[(objc - 3)], &mode)) != TCL_OK)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Any left over arg is the flag.
|
||||
*/
|
||||
flag = 0;
|
||||
if (objc == 6) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[(objc - 4)],
|
||||
lgopts, "option", TCL_EXACT, &optindex) != TCL_OK)
|
||||
return (IS_HELP(objv[(objc - 4)]));
|
||||
switch ((enum lgopts)optindex) {
|
||||
case LGNOWAIT:
|
||||
flag |= DB_LOCK_NOWAIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result = _GetThisLock(interp, dbenv, lockid, flag, &obj, mode, newname);
|
||||
if (result == TCL_OK) {
|
||||
res = NewStringObj(newname, strlen(newname));
|
||||
Tcl_SetObjResult(interp, res);
|
||||
}
|
||||
out:
|
||||
if (freeobj)
|
||||
__os_free(dbenv->env, otmp);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_LockStat --
|
||||
*
|
||||
* PUBLIC: int tcl_LockStat __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_LockStat(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
DB_LOCK_STAT *sp;
|
||||
Tcl_Obj *res;
|
||||
int result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbenv->lock_stat(dbenv, &sp, 0);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock stat");
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
/*
|
||||
* Have our stats, now construct the name value
|
||||
* list pairs and free up the memory.
|
||||
*/
|
||||
res = Tcl_NewObj();
|
||||
#ifdef HAVE_STATISTICS
|
||||
/*
|
||||
* MAKE_STAT_LIST assumes 'res' and 'error' label.
|
||||
*/
|
||||
MAKE_STAT_LIST("Region size", sp->st_regsize);
|
||||
MAKE_STAT_LIST("Last allocated locker ID", sp->st_id);
|
||||
MAKE_STAT_LIST("Current maximum unused locker ID", sp->st_cur_maxid);
|
||||
MAKE_STAT_LIST("Maximum locks", sp->st_maxlocks);
|
||||
MAKE_STAT_LIST("Maximum lockers", sp->st_maxlockers);
|
||||
MAKE_STAT_LIST("Maximum objects", sp->st_maxobjects);
|
||||
MAKE_STAT_LIST("Lock modes", sp->st_nmodes);
|
||||
MAKE_STAT_LIST("Number of lock table partitions", sp->st_partitions);
|
||||
MAKE_STAT_LIST("Current number of locks", sp->st_nlocks);
|
||||
MAKE_STAT_LIST("Maximum number of locks so far", sp->st_maxnlocks);
|
||||
MAKE_STAT_LIST("Maximum number of locks in any hash bucket",
|
||||
sp->st_maxhlocks);
|
||||
MAKE_STAT_LIST("Maximum number of lock steals for an empty partition",
|
||||
sp->st_locksteals);
|
||||
MAKE_STAT_LIST("Maximum number lock steals in any partition",
|
||||
sp->st_maxlsteals);
|
||||
MAKE_STAT_LIST("Current number of lockers", sp->st_nlockers);
|
||||
MAKE_STAT_LIST("Maximum number of lockers so far", sp->st_maxnlockers);
|
||||
MAKE_STAT_LIST("Current number of objects", sp->st_nobjects);
|
||||
MAKE_STAT_LIST("Maximum number of objects so far", sp->st_maxnobjects);
|
||||
MAKE_STAT_LIST("Maximum number of objects in any hash bucket",
|
||||
sp->st_maxhobjects);
|
||||
MAKE_STAT_LIST("Maximum number of object steals for an empty partition",
|
||||
sp->st_objectsteals);
|
||||
MAKE_STAT_LIST("Maximum number object steals in any partition",
|
||||
sp->st_maxosteals);
|
||||
MAKE_STAT_LIST("Lock requests", sp->st_nrequests);
|
||||
MAKE_STAT_LIST("Lock releases", sp->st_nreleases);
|
||||
MAKE_STAT_LIST("Lock upgrades", sp->st_nupgrade);
|
||||
MAKE_STAT_LIST("Lock downgrades", sp->st_ndowngrade);
|
||||
MAKE_STAT_LIST("Number of conflicted locks for which we waited",
|
||||
sp->st_lock_wait);
|
||||
MAKE_STAT_LIST("Number of conflicted locks for which we did not wait",
|
||||
sp->st_lock_nowait);
|
||||
MAKE_STAT_LIST("Deadlocks detected", sp->st_ndeadlocks);
|
||||
MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait);
|
||||
MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
|
||||
MAKE_STAT_LIST("Number of object allocation waits", sp->st_objs_wait);
|
||||
MAKE_STAT_LIST("Number of object allocation nowaits",
|
||||
sp->st_objs_nowait);
|
||||
MAKE_STAT_LIST("Number of locker allocation waits",
|
||||
sp->st_lockers_wait);
|
||||
MAKE_STAT_LIST("Number of locker allocation nowaits",
|
||||
sp->st_lockers_nowait);
|
||||
MAKE_STAT_LIST("Maximum hash bucket length", sp->st_hash_len);
|
||||
MAKE_STAT_LIST("Lock timeout value", sp->st_locktimeout);
|
||||
MAKE_STAT_LIST("Number of lock timeouts", sp->st_nlocktimeouts);
|
||||
MAKE_STAT_LIST("Transaction timeout value", sp->st_txntimeout);
|
||||
MAKE_STAT_LIST("Number of transaction timeouts", sp->st_ntxntimeouts);
|
||||
MAKE_STAT_LIST("Number lock partition mutex waits", sp->st_part_wait);
|
||||
MAKE_STAT_LIST("Number lock partition mutex nowaits",
|
||||
sp->st_part_nowait);
|
||||
MAKE_STAT_LIST("Maximum number waits on any lock partition mutex",
|
||||
sp->st_part_max_wait);
|
||||
MAKE_STAT_LIST("Maximum number nowaits on any lock partition mutex",
|
||||
sp->st_part_max_nowait);
|
||||
#endif
|
||||
Tcl_SetObjResult(interp, res);
|
||||
error:
|
||||
__os_ufree(dbenv->env, sp);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_LockTimeout --
|
||||
*
|
||||
* PUBLIC: int tcl_LockTimeout __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_LockTimeout(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
long timeout;
|
||||
int result, ret;
|
||||
|
||||
/*
|
||||
* One arg, the timeout.
|
||||
*/
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?timeout?");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
result = Tcl_GetLongFromObj(interp, objv[2], &timeout);
|
||||
if (result != TCL_OK)
|
||||
return (result);
|
||||
_debug_check();
|
||||
ret = dbenv->set_timeout(dbenv, (u_int32_t)timeout,
|
||||
DB_SET_LOCK_TIMEOUT);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock timeout");
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* lock_Cmd --
|
||||
* Implements the "lock" widget.
|
||||
*/
|
||||
static int
|
||||
lock_Cmd(clientData, interp, objc, objv)
|
||||
ClientData clientData; /* Lock handle */
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
{
|
||||
static const char *lkcmds[] = {
|
||||
"put",
|
||||
NULL
|
||||
};
|
||||
enum lkcmds {
|
||||
LKPUT
|
||||
};
|
||||
DB_ENV *dbenv;
|
||||
DB_LOCK *lock;
|
||||
DBTCL_INFO *lkip;
|
||||
int cmdindex, result, ret;
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
lock = (DB_LOCK *)clientData;
|
||||
lkip = _PtrToInfo((void *)lock);
|
||||
result = TCL_OK;
|
||||
|
||||
if (lock == NULL) {
|
||||
Tcl_SetResult(interp, "NULL lock", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (lkip == NULL) {
|
||||
Tcl_SetResult(interp, "NULL lock info pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
dbenv = NAME_TO_ENV(lkip->i_parent->i_name);
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
/*
|
||||
* Get the command name index from the object based on the dbcmds
|
||||
* defined above.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp,
|
||||
objv[1], lkcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
|
||||
return (IS_HELP(objv[1]));
|
||||
|
||||
switch ((enum lkcmds)cmdindex) {
|
||||
case LKPUT:
|
||||
_debug_check();
|
||||
ret = dbenv->lock_put(dbenv, lock);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"lock put");
|
||||
(void)Tcl_DeleteCommand(interp, lkip->i_name);
|
||||
_DeleteInfo(lkip);
|
||||
__os_free(dbenv->env, lock);
|
||||
break;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_LockVec --
|
||||
*
|
||||
* PUBLIC: int tcl_LockVec __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_LockVec(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* environment pointer */
|
||||
{
|
||||
static const char *lvopts[] = {
|
||||
"-nowait",
|
||||
NULL
|
||||
};
|
||||
enum lvopts {
|
||||
LVNOWAIT
|
||||
};
|
||||
static const char *lkops[] = {
|
||||
"get",
|
||||
"put",
|
||||
"put_all",
|
||||
"put_obj",
|
||||
"timeout",
|
||||
NULL
|
||||
};
|
||||
enum lkops {
|
||||
LKGET,
|
||||
LKPUT,
|
||||
LKPUTALL,
|
||||
LKPUTOBJ,
|
||||
LKTIMEOUT
|
||||
};
|
||||
|
||||
DB_LOCK *lock;
|
||||
DB_LOCKREQ list;
|
||||
DBT obj;
|
||||
Tcl_Obj **myobjv, *res, *thisop;
|
||||
void *otmp;
|
||||
u_int32_t flag, lockid;
|
||||
int freeobj, i, myobjc, optindex, result, ret;
|
||||
char *lockname, msg[MSG_SIZE], newname[MSG_SIZE];
|
||||
|
||||
result = TCL_OK;
|
||||
memset(newname, 0, MSG_SIZE);
|
||||
memset(&list, 0, sizeof(DB_LOCKREQ));
|
||||
flag = 0;
|
||||
freeobj = 0;
|
||||
otmp = NULL;
|
||||
|
||||
/*
|
||||
* If -nowait is given, it MUST be first arg.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp, objv[2],
|
||||
lvopts, "option", TCL_EXACT, &optindex) == TCL_OK) {
|
||||
switch ((enum lvopts)optindex) {
|
||||
case LVNOWAIT:
|
||||
flag |= DB_LOCK_NOWAIT;
|
||||
break;
|
||||
}
|
||||
i = 3;
|
||||
} else {
|
||||
if (IS_HELP(objv[2]) == TCL_OK)
|
||||
return (TCL_OK);
|
||||
Tcl_ResetResult(interp);
|
||||
i = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Our next arg MUST be the locker ID.
|
||||
*/
|
||||
result = _GetUInt32(interp, objv[i++], &lockid);
|
||||
if (result != TCL_OK)
|
||||
return (result);
|
||||
|
||||
/*
|
||||
* All other remaining args are operation tuples.
|
||||
* Go through sequentially to decode, execute and build
|
||||
* up list of return values.
|
||||
*/
|
||||
res = Tcl_NewListObj(0, NULL);
|
||||
while (i < objc) {
|
||||
/*
|
||||
* Get the list of the tuple.
|
||||
*/
|
||||
lock = NULL;
|
||||
result = Tcl_ListObjGetElements(interp, objv[i],
|
||||
&myobjc, &myobjv);
|
||||
if (result == TCL_OK)
|
||||
i++;
|
||||
else
|
||||
break;
|
||||
/*
|
||||
* First we will set up the list of requests.
|
||||
* We will make a "second pass" after we get back
|
||||
* the results from the lock_vec call to create
|
||||
* the return list.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp, myobjv[0],
|
||||
lkops, "option", TCL_EXACT, &optindex) != TCL_OK) {
|
||||
result = IS_HELP(myobjv[0]);
|
||||
goto error;
|
||||
}
|
||||
switch ((enum lkops)optindex) {
|
||||
case LKGET:
|
||||
if (myobjc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, myobjv,
|
||||
"{get obj mode}");
|
||||
result = TCL_ERROR;
|
||||
goto error;
|
||||
}
|
||||
result = _LockMode(interp, myobjv[2], &list.mode);
|
||||
if (result != TCL_OK)
|
||||
goto error;
|
||||
ret = _CopyObjBytes(interp, myobjv[1], &otmp,
|
||||
&obj.size, &freeobj);
|
||||
if (ret != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "lock vec");
|
||||
return (result);
|
||||
}
|
||||
obj.data = otmp;
|
||||
ret = _GetThisLock(interp, dbenv, lockid, flag,
|
||||
&obj, list.mode, newname);
|
||||
if (ret != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "lock vec");
|
||||
thisop = Tcl_NewIntObj(ret);
|
||||
(void)Tcl_ListObjAppendElement(interp, res,
|
||||
thisop);
|
||||
goto error;
|
||||
}
|
||||
thisop = NewStringObj(newname, strlen(newname));
|
||||
(void)Tcl_ListObjAppendElement(interp, res, thisop);
|
||||
if (freeobj && otmp != NULL) {
|
||||
__os_free(dbenv->env, otmp);
|
||||
freeobj = 0;
|
||||
}
|
||||
continue;
|
||||
case LKPUT:
|
||||
if (myobjc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, myobjv,
|
||||
"{put lock}");
|
||||
result = TCL_ERROR;
|
||||
goto error;
|
||||
}
|
||||
list.op = DB_LOCK_PUT;
|
||||
lockname = Tcl_GetStringFromObj(myobjv[1], NULL);
|
||||
lock = NAME_TO_LOCK(lockname);
|
||||
if (lock == NULL) {
|
||||
snprintf(msg, MSG_SIZE, "Invalid lock: %s\n",
|
||||
lockname);
|
||||
Tcl_SetResult(interp, msg, TCL_VOLATILE);
|
||||
result = TCL_ERROR;
|
||||
goto error;
|
||||
}
|
||||
list.lock = *lock;
|
||||
break;
|
||||
case LKPUTALL:
|
||||
if (myobjc != 1) {
|
||||
Tcl_WrongNumArgs(interp, 1, myobjv,
|
||||
"{put_all}");
|
||||
result = TCL_ERROR;
|
||||
goto error;
|
||||
}
|
||||
list.op = DB_LOCK_PUT_ALL;
|
||||
break;
|
||||
case LKPUTOBJ:
|
||||
if (myobjc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, myobjv,
|
||||
"{put_obj obj}");
|
||||
result = TCL_ERROR;
|
||||
goto error;
|
||||
}
|
||||
list.op = DB_LOCK_PUT_OBJ;
|
||||
ret = _CopyObjBytes(interp, myobjv[1], &otmp,
|
||||
&obj.size, &freeobj);
|
||||
if (ret != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "lock vec");
|
||||
return (result);
|
||||
}
|
||||
obj.data = otmp;
|
||||
list.obj = &obj;
|
||||
break;
|
||||
case LKTIMEOUT:
|
||||
list.op = DB_LOCK_TIMEOUT;
|
||||
break;
|
||||
|
||||
}
|
||||
/*
|
||||
* We get here, we have set up our request, now call
|
||||
* lock_vec.
|
||||
*/
|
||||
_debug_check();
|
||||
ret = dbenv->lock_vec(dbenv, lockid, flag, &list, 1, NULL);
|
||||
/*
|
||||
* Now deal with whether or not the operation succeeded.
|
||||
* Get's were done above, all these are only puts.
|
||||
*/
|
||||
thisop = Tcl_NewIntObj(ret);
|
||||
result = Tcl_ListObjAppendElement(interp, res, thisop);
|
||||
if (ret != 0 && result == TCL_OK)
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "lock put");
|
||||
if (freeobj && otmp != NULL) {
|
||||
__os_free(dbenv->env, otmp);
|
||||
freeobj = 0;
|
||||
}
|
||||
/*
|
||||
* We did a put of some kind. Since we did that,
|
||||
* we have to delete the commands associated with
|
||||
* any of the locks we just put.
|
||||
*/
|
||||
_LockPutInfo(interp, list.op, lock, lockid, &obj);
|
||||
}
|
||||
|
||||
if (result == TCL_OK && res)
|
||||
Tcl_SetObjResult(interp, res);
|
||||
error:
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
_LockMode(interp, obj, mode)
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *obj;
|
||||
db_lockmode_t *mode;
|
||||
{
|
||||
static const char *lkmode[] = {
|
||||
"ng",
|
||||
"read",
|
||||
"write",
|
||||
"iwrite",
|
||||
"iread",
|
||||
"iwr",
|
||||
NULL
|
||||
};
|
||||
enum lkmode {
|
||||
LK_NG,
|
||||
LK_READ,
|
||||
LK_WRITE,
|
||||
LK_IWRITE,
|
||||
LK_IREAD,
|
||||
LK_IWR
|
||||
};
|
||||
int optindex;
|
||||
|
||||
if (Tcl_GetIndexFromObj(interp, obj, lkmode, "option",
|
||||
TCL_EXACT, &optindex) != TCL_OK)
|
||||
return (IS_HELP(obj));
|
||||
switch ((enum lkmode)optindex) {
|
||||
case LK_NG:
|
||||
*mode = DB_LOCK_NG;
|
||||
break;
|
||||
case LK_READ:
|
||||
*mode = DB_LOCK_READ;
|
||||
break;
|
||||
case LK_WRITE:
|
||||
*mode = DB_LOCK_WRITE;
|
||||
break;
|
||||
case LK_IREAD:
|
||||
*mode = DB_LOCK_IREAD;
|
||||
break;
|
||||
case LK_IWRITE:
|
||||
*mode = DB_LOCK_IWRITE;
|
||||
break;
|
||||
case LK_IWR:
|
||||
*mode = DB_LOCK_IWR;
|
||||
break;
|
||||
}
|
||||
return (TCL_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
_LockPutInfo(interp, op, lock, lockid, objp)
|
||||
Tcl_Interp *interp;
|
||||
db_lockop_t op;
|
||||
DB_LOCK *lock;
|
||||
u_int32_t lockid;
|
||||
DBT *objp;
|
||||
{
|
||||
DBTCL_INFO *p, *nextp;
|
||||
int found;
|
||||
|
||||
for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) {
|
||||
found = 0;
|
||||
nextp = LIST_NEXT(p, entries);
|
||||
if ((op == DB_LOCK_PUT && (p->i_lock == lock)) ||
|
||||
(op == DB_LOCK_PUT_ALL && p->i_locker == lockid) ||
|
||||
(op == DB_LOCK_PUT_OBJ && p->i_lockobj.data &&
|
||||
memcmp(p->i_lockobj.data, objp->data, objp->size) == 0))
|
||||
found = 1;
|
||||
if (found) {
|
||||
(void)Tcl_DeleteCommand(interp, p->i_name);
|
||||
__os_free(NULL, p->i_lock);
|
||||
_DeleteInfo(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_GetThisLock(interp, dbenv, lockid, flag, objp, mode, newname)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
DB_ENV *dbenv; /* Env handle */
|
||||
u_int32_t lockid; /* Locker ID */
|
||||
u_int32_t flag; /* Lock flag */
|
||||
DBT *objp; /* Object to lock */
|
||||
db_lockmode_t mode; /* Lock mode */
|
||||
char *newname; /* New command name */
|
||||
{
|
||||
DBTCL_INFO *envip, *ip;
|
||||
DB_LOCK *lock;
|
||||
int result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
envip = _PtrToInfo((void *)dbenv);
|
||||
if (envip == NULL) {
|
||||
Tcl_SetResult(interp, "Could not find env info\n", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
snprintf(newname, MSG_SIZE, "%s.lock%d",
|
||||
envip->i_name, envip->i_envlockid);
|
||||
ip = _NewInfo(interp, NULL, newname, I_LOCK);
|
||||
if (ip == NULL) {
|
||||
Tcl_SetResult(interp, "Could not set up info",
|
||||
TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
ret = __os_malloc(dbenv->env, sizeof(DB_LOCK), &lock);
|
||||
if (ret != 0) {
|
||||
Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbenv->lock_get(dbenv, lockid, flag, objp, mode, lock);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock get");
|
||||
if (result == TCL_ERROR) {
|
||||
__os_free(dbenv->env, lock);
|
||||
_DeleteInfo(ip);
|
||||
return (result);
|
||||
}
|
||||
/*
|
||||
* Success. Set up return. Set up new info
|
||||
* and command widget for this lock.
|
||||
*/
|
||||
ret = __os_malloc(dbenv->env, objp->size, &ip->i_lockobj.data);
|
||||
if (ret != 0) {
|
||||
Tcl_SetResult(interp, "Could not duplicate obj",
|
||||
TCL_STATIC);
|
||||
(void)dbenv->lock_put(dbenv, lock);
|
||||
__os_free(dbenv->env, lock);
|
||||
_DeleteInfo(ip);
|
||||
result = TCL_ERROR;
|
||||
goto error;
|
||||
}
|
||||
memcpy(ip->i_lockobj.data, objp->data, objp->size);
|
||||
ip->i_lockobj.size = objp->size;
|
||||
envip->i_envlockid++;
|
||||
ip->i_parent = envip;
|
||||
ip->i_locker = lockid;
|
||||
_SetInfoData(ip, lock);
|
||||
(void)Tcl_CreateObjCommand(interp, newname,
|
||||
(Tcl_ObjCmdProc *)lock_Cmd, (ClientData)lock, NULL);
|
||||
error:
|
||||
return (result);
|
||||
}
|
||||
#endif
|
||||
770
tcl/tcl_log.c
Normal file
770
tcl/tcl_log.c
Normal file
@@ -0,0 +1,770 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1999,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: tcl_log.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#include <tcl.h>
|
||||
#endif
|
||||
#include "dbinc/log.h"
|
||||
#include "dbinc/tcl_db.h"
|
||||
|
||||
#ifdef CONFIG_TEST
|
||||
static int tcl_LogcGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_LOGC *));
|
||||
|
||||
/*
|
||||
* tcl_LogArchive --
|
||||
*
|
||||
* PUBLIC: int tcl_LogArchive __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_LogArchive(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
static const char *archopts[] = {
|
||||
"-arch_abs", "-arch_data", "-arch_log", "-arch_remove",
|
||||
NULL
|
||||
};
|
||||
enum archopts {
|
||||
ARCH_ABS, ARCH_DATA, ARCH_LOG, ARCH_REMOVE
|
||||
};
|
||||
Tcl_Obj *fileobj, *res;
|
||||
u_int32_t flag;
|
||||
int i, optindex, result, ret;
|
||||
char **file, **list;
|
||||
|
||||
result = TCL_OK;
|
||||
flag = 0;
|
||||
/*
|
||||
* Get the flag index from the object based on the options
|
||||
* defined above.
|
||||
*/
|
||||
i = 2;
|
||||
while (i < objc) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i],
|
||||
archopts, "option", TCL_EXACT, &optindex) != TCL_OK)
|
||||
return (IS_HELP(objv[i]));
|
||||
i++;
|
||||
switch ((enum archopts)optindex) {
|
||||
case ARCH_ABS:
|
||||
flag |= DB_ARCH_ABS;
|
||||
break;
|
||||
case ARCH_DATA:
|
||||
flag |= DB_ARCH_DATA;
|
||||
break;
|
||||
case ARCH_LOG:
|
||||
flag |= DB_ARCH_LOG;
|
||||
break;
|
||||
case ARCH_REMOVE:
|
||||
flag |= DB_ARCH_REMOVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_debug_check();
|
||||
list = NULL;
|
||||
ret = dbenv->log_archive(dbenv, &list, flag);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log archive");
|
||||
if (result == TCL_OK) {
|
||||
res = Tcl_NewListObj(0, NULL);
|
||||
for (file = list; file != NULL && *file != NULL; file++) {
|
||||
fileobj = NewStringObj(*file, strlen(*file));
|
||||
result = Tcl_ListObjAppendElement(interp, res, fileobj);
|
||||
if (result != TCL_OK)
|
||||
break;
|
||||
}
|
||||
Tcl_SetObjResult(interp, res);
|
||||
}
|
||||
if (list != NULL)
|
||||
__os_ufree(dbenv->env, list);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_LogCompare --
|
||||
*
|
||||
* PUBLIC: int tcl_LogCompare __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*));
|
||||
*/
|
||||
int
|
||||
tcl_LogCompare(interp, objc, objv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
{
|
||||
DB_LSN lsn0, lsn1;
|
||||
Tcl_Obj *res;
|
||||
int result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
/*
|
||||
* No flags, must be 4 args.
|
||||
*/
|
||||
if (objc != 4) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "lsn1 lsn2");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
result = _GetLsn(interp, objv[2], &lsn0);
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
result = _GetLsn(interp, objv[3], &lsn1);
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
|
||||
_debug_check();
|
||||
ret = log_compare(&lsn0, &lsn1);
|
||||
res = Tcl_NewIntObj(ret);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_LogFile --
|
||||
*
|
||||
* PUBLIC: int tcl_LogFile __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_LogFile(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
DB_LSN lsn;
|
||||
Tcl_Obj *res;
|
||||
size_t len;
|
||||
int result, ret;
|
||||
char *name;
|
||||
|
||||
result = TCL_OK;
|
||||
/*
|
||||
* No flags, must be 3 args.
|
||||
*/
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "lsn");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
result = _GetLsn(interp, objv[2], &lsn);
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
|
||||
len = MSG_SIZE;
|
||||
ret = ENOMEM;
|
||||
name = NULL;
|
||||
while (ret == ENOMEM) {
|
||||
if (name != NULL)
|
||||
__os_free(dbenv->env, name);
|
||||
ret = __os_malloc(dbenv->env, len, &name);
|
||||
if (ret != 0) {
|
||||
Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
|
||||
break;
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbenv->log_file(dbenv, &lsn, name, len);
|
||||
len *= 2;
|
||||
}
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log_file");
|
||||
if (ret == 0) {
|
||||
res = NewStringObj(name, strlen(name));
|
||||
Tcl_SetObjResult(interp, res);
|
||||
}
|
||||
|
||||
if (name != NULL)
|
||||
__os_free(dbenv->env, name);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_LogFlush --
|
||||
*
|
||||
* PUBLIC: int tcl_LogFlush __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_LogFlush(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
DB_LSN lsn, *lsnp;
|
||||
int result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
/*
|
||||
* No flags, must be 2 or 3 args.
|
||||
*/
|
||||
if (objc > 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?lsn?");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
if (objc == 3) {
|
||||
lsnp = &lsn;
|
||||
result = _GetLsn(interp, objv[2], &lsn);
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
} else
|
||||
lsnp = NULL;
|
||||
|
||||
_debug_check();
|
||||
ret = dbenv->log_flush(dbenv, lsnp);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log_flush");
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_LogGet --
|
||||
*
|
||||
* PUBLIC: int tcl_LogGet __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_LogGet(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
|
||||
COMPQUIET(objv, NULL);
|
||||
COMPQUIET(objc, 0);
|
||||
COMPQUIET(dbenv, NULL);
|
||||
|
||||
Tcl_SetResult(interp, "FAIL: log_get deprecated\n", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_LogPut --
|
||||
*
|
||||
* PUBLIC: int tcl_LogPut __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_LogPut(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
static const char *logputopts[] = {
|
||||
"-flush",
|
||||
NULL
|
||||
};
|
||||
enum logputopts {
|
||||
LOGPUT_FLUSH
|
||||
};
|
||||
DB_LSN lsn;
|
||||
DBT data;
|
||||
Tcl_Obj *intobj, *res;
|
||||
void *dtmp;
|
||||
u_int32_t flag;
|
||||
int freedata, optindex, result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
flag = 0;
|
||||
freedata = 0;
|
||||
if (objc < 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-args? record");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Data/record must be the last arg.
|
||||
*/
|
||||
memset(&data, 0, sizeof(data));
|
||||
ret = _CopyObjBytes(interp, objv[objc-1], &dtmp,
|
||||
&data.size, &freedata);
|
||||
if (ret != 0) {
|
||||
result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "log put");
|
||||
return (result);
|
||||
}
|
||||
data.data = dtmp;
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the options
|
||||
* defined above.
|
||||
*/
|
||||
if (objc == 4) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[2],
|
||||
logputopts, "option", TCL_EXACT, &optindex) != TCL_OK) {
|
||||
return (IS_HELP(objv[2]));
|
||||
}
|
||||
switch ((enum logputopts)optindex) {
|
||||
case LOGPUT_FLUSH:
|
||||
flag = DB_FLUSH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
|
||||
_debug_check();
|
||||
ret = dbenv->log_put(dbenv, &lsn, &data, flag);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log_put");
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
res = Tcl_NewListObj(0, NULL);
|
||||
intobj = Tcl_NewWideIntObj((Tcl_WideInt)lsn.file);
|
||||
result = Tcl_ListObjAppendElement(interp, res, intobj);
|
||||
intobj = Tcl_NewWideIntObj((Tcl_WideInt)lsn.offset);
|
||||
result = Tcl_ListObjAppendElement(interp, res, intobj);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
if (freedata)
|
||||
__os_free(NULL, dtmp);
|
||||
return (result);
|
||||
}
|
||||
/*
|
||||
* tcl_LogStat --
|
||||
*
|
||||
* PUBLIC: int tcl_LogStat __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_LogStat(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
DB_LOG_STAT *sp;
|
||||
Tcl_Obj *res;
|
||||
int result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbenv->log_stat(dbenv, &sp, 0);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log stat");
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
|
||||
/*
|
||||
* Have our stats, now construct the name value
|
||||
* list pairs and free up the memory.
|
||||
*/
|
||||
res = Tcl_NewObj();
|
||||
/*
|
||||
* MAKE_STAT_LIST assumes 'res' and 'error' label.
|
||||
*/
|
||||
#ifdef HAVE_STATISTICS
|
||||
MAKE_STAT_LIST("Magic", sp->st_magic);
|
||||
MAKE_STAT_LIST("Log file Version", sp->st_version);
|
||||
MAKE_STAT_LIST("Region size", sp->st_regsize);
|
||||
MAKE_STAT_LIST("Log file mode", sp->st_mode);
|
||||
MAKE_STAT_LIST("Log record cache size", sp->st_lg_bsize);
|
||||
MAKE_STAT_LIST("Current log file size", sp->st_lg_size);
|
||||
MAKE_STAT_LIST("Log file records written", sp->st_record);
|
||||
MAKE_STAT_LIST("Mbytes written", sp->st_w_mbytes);
|
||||
MAKE_STAT_LIST("Bytes written (over Mb)", sp->st_w_bytes);
|
||||
MAKE_STAT_LIST("Mbytes written since checkpoint", sp->st_wc_mbytes);
|
||||
MAKE_STAT_LIST("Bytes written (over Mb) since checkpoint",
|
||||
sp->st_wc_bytes);
|
||||
MAKE_STAT_LIST("Times log written", sp->st_wcount);
|
||||
MAKE_STAT_LIST("Times log written because cache filled up",
|
||||
sp->st_wcount_fill);
|
||||
MAKE_STAT_LIST("Times log read from disk", sp->st_rcount);
|
||||
MAKE_STAT_LIST("Times log flushed to disk", sp->st_scount);
|
||||
MAKE_STAT_LIST("Current log file number", sp->st_cur_file);
|
||||
MAKE_STAT_LIST("Current log file offset", sp->st_cur_offset);
|
||||
MAKE_STAT_LIST("On-disk log file number", sp->st_disk_file);
|
||||
MAKE_STAT_LIST("On-disk log file offset", sp->st_disk_offset);
|
||||
MAKE_STAT_LIST("Max commits in a log flush", sp->st_maxcommitperflush);
|
||||
MAKE_STAT_LIST("Min commits in a log flush", sp->st_mincommitperflush);
|
||||
MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait);
|
||||
MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
|
||||
#endif
|
||||
Tcl_SetObjResult(interp, res);
|
||||
error:
|
||||
__os_ufree(dbenv->env, sp);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* logc_Cmd --
|
||||
* Implements the log cursor command.
|
||||
*
|
||||
* PUBLIC: int logc_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
|
||||
*/
|
||||
int
|
||||
logc_Cmd(clientData, interp, objc, objv)
|
||||
ClientData clientData; /* Cursor handle */
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
{
|
||||
static const char *logccmds[] = {
|
||||
"close",
|
||||
"get",
|
||||
"version",
|
||||
NULL
|
||||
};
|
||||
enum logccmds {
|
||||
LOGCCLOSE,
|
||||
LOGCGET,
|
||||
LOGCVERSION
|
||||
};
|
||||
DB_LOGC *logc;
|
||||
DBTCL_INFO *logcip;
|
||||
Tcl_Obj *res;
|
||||
u_int32_t version;
|
||||
int cmdindex, result, ret;
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
logc = (DB_LOGC *)clientData;
|
||||
logcip = _PtrToInfo((void *)logc);
|
||||
result = TCL_OK;
|
||||
|
||||
if (objc <= 1) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (logc == NULL) {
|
||||
Tcl_SetResult(interp, "NULL logc pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (logcip == NULL) {
|
||||
Tcl_SetResult(interp, "NULL logc info pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the berkdbcmds
|
||||
* defined above.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp, objv[1], logccmds, "command",
|
||||
TCL_EXACT, &cmdindex) != TCL_OK)
|
||||
return (IS_HELP(objv[1]));
|
||||
switch ((enum logccmds)cmdindex) {
|
||||
case LOGCCLOSE:
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc > 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = logc->close(logc, 0);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"logc close");
|
||||
if (result == TCL_OK) {
|
||||
(void)Tcl_DeleteCommand(interp, logcip->i_name);
|
||||
_DeleteInfo(logcip);
|
||||
}
|
||||
break;
|
||||
case LOGCGET:
|
||||
result = tcl_LogcGet(interp, objc, objv, logc);
|
||||
break;
|
||||
case LOGCVERSION:
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc > 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = logc->version(logc, &version, 0);
|
||||
if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"logc version")) == TCL_OK) {
|
||||
res = Tcl_NewIntObj((int)version);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
tcl_LogcGet(interp, objc, objv, logc)
|
||||
Tcl_Interp *interp;
|
||||
int objc;
|
||||
Tcl_Obj * CONST *objv;
|
||||
DB_LOGC *logc;
|
||||
{
|
||||
static const char *logcgetopts[] = {
|
||||
"-current",
|
||||
"-first",
|
||||
"-last",
|
||||
"-next",
|
||||
"-prev",
|
||||
"-set",
|
||||
NULL
|
||||
};
|
||||
enum logcgetopts {
|
||||
LOGCGET_CURRENT,
|
||||
LOGCGET_FIRST,
|
||||
LOGCGET_LAST,
|
||||
LOGCGET_NEXT,
|
||||
LOGCGET_PREV,
|
||||
LOGCGET_SET
|
||||
};
|
||||
DB_LSN lsn;
|
||||
DBT data;
|
||||
Tcl_Obj *dataobj, *lsnlist, *myobjv[2], *res;
|
||||
u_int32_t flag;
|
||||
int i, myobjc, optindex, result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
res = NULL;
|
||||
flag = 0;
|
||||
|
||||
if (objc < 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-args? lsn");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the options
|
||||
* defined above.
|
||||
*/
|
||||
i = 2;
|
||||
while (i < objc) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i],
|
||||
logcgetopts, "option", TCL_EXACT, &optindex) != TCL_OK)
|
||||
return (IS_HELP(objv[i]));
|
||||
i++;
|
||||
switch ((enum logcgetopts)optindex) {
|
||||
case LOGCGET_CURRENT:
|
||||
FLAG_CHECK(flag);
|
||||
flag |= DB_CURRENT;
|
||||
break;
|
||||
case LOGCGET_FIRST:
|
||||
FLAG_CHECK(flag);
|
||||
flag |= DB_FIRST;
|
||||
break;
|
||||
case LOGCGET_LAST:
|
||||
FLAG_CHECK(flag);
|
||||
flag |= DB_LAST;
|
||||
break;
|
||||
case LOGCGET_NEXT:
|
||||
FLAG_CHECK(flag);
|
||||
flag |= DB_NEXT;
|
||||
break;
|
||||
case LOGCGET_PREV:
|
||||
FLAG_CHECK(flag);
|
||||
flag |= DB_PREV;
|
||||
break;
|
||||
case LOGCGET_SET:
|
||||
FLAG_CHECK(flag);
|
||||
flag |= DB_SET;
|
||||
if (i == objc) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-set lsn?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
result = _GetLsn(interp, objv[i++], &lsn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
_debug_check();
|
||||
ret = logc->get(logc, &lsn, &data, flag);
|
||||
|
||||
res = Tcl_NewListObj(0, NULL);
|
||||
if (res == NULL)
|
||||
goto memerr;
|
||||
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* Success. Set up return list as {LSN data} where LSN
|
||||
* is a sublist {file offset}.
|
||||
*/
|
||||
myobjc = 2;
|
||||
myobjv[0] = Tcl_NewWideIntObj((Tcl_WideInt)lsn.file);
|
||||
myobjv[1] = Tcl_NewWideIntObj((Tcl_WideInt)lsn.offset);
|
||||
lsnlist = Tcl_NewListObj(myobjc, myobjv);
|
||||
if (lsnlist == NULL)
|
||||
goto memerr;
|
||||
|
||||
result = Tcl_ListObjAppendElement(interp, res, lsnlist);
|
||||
dataobj = NewStringObj(data.data, data.size);
|
||||
if (dataobj == NULL) {
|
||||
goto memerr;
|
||||
}
|
||||
result = Tcl_ListObjAppendElement(interp, res, dataobj);
|
||||
} else
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_LGGET(ret),
|
||||
"DB_LOGC->get");
|
||||
|
||||
Tcl_SetObjResult(interp, res);
|
||||
|
||||
if (0) {
|
||||
memerr: if (res != NULL) {
|
||||
Tcl_DecrRefCount(res);
|
||||
}
|
||||
Tcl_SetResult(interp, "allocation failed", TCL_STATIC);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static const char *confwhich[] = {
|
||||
"autoremove",
|
||||
"direct",
|
||||
"dsync",
|
||||
"inmemory",
|
||||
"zero",
|
||||
NULL
|
||||
};
|
||||
enum logwhich {
|
||||
LOGCONF_AUTO,
|
||||
LOGCONF_DIRECT,
|
||||
LOGCONF_DSYNC,
|
||||
LOGCONF_INMEMORY,
|
||||
LOGCONF_ZERO
|
||||
};
|
||||
|
||||
/*
|
||||
* tcl_LogConfig --
|
||||
* Call DB_ENV->rep_set_config().
|
||||
*
|
||||
* PUBLIC: int tcl_LogConfig
|
||||
* PUBLIC: __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *));
|
||||
*/
|
||||
int
|
||||
tcl_LogConfig(interp, dbenv, list)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
Tcl_Obj *list; /* {which on|off} */
|
||||
{
|
||||
static const char *confonoff[] = {
|
||||
"off",
|
||||
"on",
|
||||
NULL
|
||||
};
|
||||
enum confonoff {
|
||||
LOGCONF_OFF,
|
||||
LOGCONF_ON
|
||||
};
|
||||
Tcl_Obj **myobjv, *onoff, *which;
|
||||
int myobjc, on, optindex, result, ret;
|
||||
u_int32_t wh;
|
||||
|
||||
result = Tcl_ListObjGetElements(interp, list, &myobjc, &myobjv);
|
||||
if (myobjc != 2)
|
||||
Tcl_WrongNumArgs(interp, 2, myobjv, "?{which onoff}?");
|
||||
which = myobjv[0];
|
||||
onoff = myobjv[1];
|
||||
if (result != TCL_OK)
|
||||
return (result);
|
||||
if (Tcl_GetIndexFromObj(interp, which, confwhich, "option",
|
||||
TCL_EXACT, &optindex) != TCL_OK)
|
||||
return (IS_HELP(which));
|
||||
|
||||
switch ((enum logwhich)optindex) {
|
||||
case LOGCONF_AUTO:
|
||||
wh = DB_LOG_AUTO_REMOVE;
|
||||
break;
|
||||
case LOGCONF_DIRECT:
|
||||
wh = DB_LOG_DIRECT;
|
||||
break;
|
||||
case LOGCONF_DSYNC:
|
||||
wh = DB_LOG_DSYNC;
|
||||
break;
|
||||
case LOGCONF_INMEMORY:
|
||||
wh = DB_LOG_IN_MEMORY;
|
||||
break;
|
||||
case LOGCONF_ZERO:
|
||||
wh = DB_LOG_ZERO;
|
||||
break;
|
||||
default:
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (Tcl_GetIndexFromObj(interp, onoff, confonoff, "option",
|
||||
TCL_EXACT, &optindex) != TCL_OK)
|
||||
return (IS_HELP(onoff));
|
||||
switch ((enum confonoff)optindex) {
|
||||
case LOGCONF_OFF:
|
||||
on = 0;
|
||||
break;
|
||||
case LOGCONF_ON:
|
||||
on = 1;
|
||||
break;
|
||||
default:
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
ret = dbenv->log_set_config(dbenv, wh, on);
|
||||
return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"env rep_config"));
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_LogGetConfig --
|
||||
* Call DB_ENV->rep_get_config().
|
||||
*
|
||||
* PUBLIC: int tcl_LogGetConfig
|
||||
* PUBLIC: __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *));
|
||||
*/
|
||||
int
|
||||
tcl_LogGetConfig(interp, dbenv, which)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
Tcl_Obj *which; /* which flag */
|
||||
{
|
||||
Tcl_Obj *res;
|
||||
int on, optindex, result, ret;
|
||||
u_int32_t wh;
|
||||
|
||||
if (Tcl_GetIndexFromObj(interp, which, confwhich, "option",
|
||||
TCL_EXACT, &optindex) != TCL_OK)
|
||||
return (IS_HELP(which));
|
||||
|
||||
res = NULL;
|
||||
switch ((enum logwhich)optindex) {
|
||||
case LOGCONF_AUTO:
|
||||
wh = DB_LOG_AUTO_REMOVE;
|
||||
break;
|
||||
case LOGCONF_DIRECT:
|
||||
wh = DB_LOG_DIRECT;
|
||||
break;
|
||||
case LOGCONF_DSYNC:
|
||||
wh = DB_LOG_DSYNC;
|
||||
break;
|
||||
case LOGCONF_INMEMORY:
|
||||
wh = DB_LOG_IN_MEMORY;
|
||||
break;
|
||||
case LOGCONF_ZERO:
|
||||
wh = DB_LOG_ZERO;
|
||||
break;
|
||||
default:
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
ret = dbenv->log_get_config(dbenv, wh, &on);
|
||||
if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"env log_config")) == TCL_OK) {
|
||||
res = Tcl_NewIntObj(on);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
#endif
|
||||
941
tcl/tcl_mp.c
Normal file
941
tcl/tcl_mp.c
Normal file
@@ -0,0 +1,941 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1999,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: tcl_mp.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#include <tcl.h>
|
||||
#endif
|
||||
#include "dbinc/tcl_db.h"
|
||||
|
||||
/*
|
||||
* Prototypes for procedures defined later in this file:
|
||||
*/
|
||||
#ifdef CONFIG_TEST
|
||||
static int mp_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
|
||||
static int pg_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
|
||||
static int tcl_MpGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
|
||||
DB_MPOOLFILE *, DBTCL_INFO *));
|
||||
static int tcl_Pg __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
|
||||
void *, DB_MPOOLFILE *, DBTCL_INFO *));
|
||||
static int tcl_PgInit __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
|
||||
void *, DBTCL_INFO *));
|
||||
static int tcl_PgIsset __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
|
||||
void *, DBTCL_INFO *));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _MpInfoDelete --
|
||||
* Removes "sub" mp page info structures that are children
|
||||
* of this mp.
|
||||
*
|
||||
* PUBLIC: void _MpInfoDelete __P((Tcl_Interp *, DBTCL_INFO *));
|
||||
*/
|
||||
void
|
||||
_MpInfoDelete(interp, mpip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
DBTCL_INFO *mpip; /* Info for mp */
|
||||
{
|
||||
DBTCL_INFO *nextp, *p;
|
||||
|
||||
for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) {
|
||||
/*
|
||||
* Check if this info structure "belongs" to this
|
||||
* mp. Remove its commands and info structure.
|
||||
*/
|
||||
nextp = LIST_NEXT(p, entries);
|
||||
if (p->i_parent == mpip && p->i_type == I_PG) {
|
||||
(void)Tcl_DeleteCommand(interp, p->i_name);
|
||||
_DeleteInfo(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TEST
|
||||
/*
|
||||
* tcl_MpSync --
|
||||
*
|
||||
* PUBLIC: int tcl_MpSync __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_MpSync(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
|
||||
DB_LSN lsn, *lsnp;
|
||||
int result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
lsnp = NULL;
|
||||
/*
|
||||
* No flags, must be 3 args.
|
||||
*/
|
||||
if (objc == 3) {
|
||||
result = _GetLsn(interp, objv[2], &lsn);
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
lsnp = &lsn;
|
||||
}
|
||||
else if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "lsn");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
_debug_check();
|
||||
ret = dbenv->memp_sync(dbenv, lsnp);
|
||||
return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "memp sync"));
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_MpTrickle --
|
||||
*
|
||||
* PUBLIC: int tcl_MpTrickle __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_MpTrickle(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
|
||||
Tcl_Obj *res;
|
||||
int pages, percent, result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
/*
|
||||
* No flags, must be 3 args.
|
||||
*/
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "percent");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
result = Tcl_GetIntFromObj(interp, objv[2], &percent);
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
|
||||
_debug_check();
|
||||
ret = dbenv->memp_trickle(dbenv, percent, &pages);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "memp trickle");
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
|
||||
res = Tcl_NewIntObj(pages);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_Mp --
|
||||
*
|
||||
* PUBLIC: int tcl_Mp __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *));
|
||||
*/
|
||||
int
|
||||
tcl_Mp(interp, objc, objv, dbenv, envip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
DBTCL_INFO *envip; /* Info pointer */
|
||||
{
|
||||
static const char *mpopts[] = {
|
||||
"-create",
|
||||
"-mode",
|
||||
"-multiversion",
|
||||
"-nommap",
|
||||
"-pagesize",
|
||||
"-rdonly",
|
||||
NULL
|
||||
};
|
||||
enum mpopts {
|
||||
MPCREATE,
|
||||
MPMODE,
|
||||
MPMULTIVERSION,
|
||||
MPNOMMAP,
|
||||
MPPAGE,
|
||||
MPRDONLY
|
||||
};
|
||||
DBTCL_INFO *ip;
|
||||
DB_MPOOLFILE *mpf;
|
||||
Tcl_Obj *res;
|
||||
u_int32_t flag;
|
||||
int i, pgsize, mode, optindex, result, ret;
|
||||
char *file, newname[MSG_SIZE];
|
||||
|
||||
result = TCL_OK;
|
||||
i = 2;
|
||||
flag = 0;
|
||||
mode = 0;
|
||||
pgsize = 0;
|
||||
memset(newname, 0, MSG_SIZE);
|
||||
while (i < objc) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i],
|
||||
mpopts, "option", TCL_EXACT, &optindex) != TCL_OK) {
|
||||
/*
|
||||
* Reset the result so we don't get an errant
|
||||
* error message if there is another error.
|
||||
* This arg is the file name.
|
||||
*/
|
||||
if (IS_HELP(objv[i]) == TCL_OK)
|
||||
return (TCL_OK);
|
||||
Tcl_ResetResult(interp);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
switch ((enum mpopts)optindex) {
|
||||
case MPCREATE:
|
||||
flag |= DB_CREATE;
|
||||
break;
|
||||
case MPMODE:
|
||||
if (i >= objc) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"?-mode mode?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Don't need to check result here because
|
||||
* if TCL_ERROR, the error message is already
|
||||
* set up, and we'll bail out below. If ok,
|
||||
* the mode is set and we go on.
|
||||
*/
|
||||
result = Tcl_GetIntFromObj(interp, objv[i++], &mode);
|
||||
break;
|
||||
case MPMULTIVERSION:
|
||||
flag |= DB_MULTIVERSION;
|
||||
break;
|
||||
case MPNOMMAP:
|
||||
flag |= DB_NOMMAP;
|
||||
break;
|
||||
case MPPAGE:
|
||||
if (i >= objc) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"?-pagesize size?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Don't need to check result here because
|
||||
* if TCL_ERROR, the error message is already
|
||||
* set up, and we'll bail out below. If ok,
|
||||
* the mode is set and we go on.
|
||||
*/
|
||||
result = Tcl_GetIntFromObj(interp, objv[i++], &pgsize);
|
||||
break;
|
||||
case MPRDONLY:
|
||||
flag |= DB_RDONLY;
|
||||
break;
|
||||
}
|
||||
if (result != TCL_OK)
|
||||
goto error;
|
||||
}
|
||||
/*
|
||||
* Any left over arg is a file name. It better be the last arg.
|
||||
*/
|
||||
file = NULL;
|
||||
if (i != objc) {
|
||||
if (i != objc - 1) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?args? ?file?");
|
||||
result = TCL_ERROR;
|
||||
goto error;
|
||||
}
|
||||
file = Tcl_GetStringFromObj(objv[i++], NULL);
|
||||
}
|
||||
|
||||
snprintf(newname, sizeof(newname), "%s.mp%d",
|
||||
envip->i_name, envip->i_envmpid);
|
||||
ip = _NewInfo(interp, NULL, newname, I_MP);
|
||||
if (ip == NULL) {
|
||||
Tcl_SetResult(interp, "Could not set up info",
|
||||
TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
_debug_check();
|
||||
if ((ret = dbenv->memp_fcreate(dbenv, &mpf, 0)) != 0) {
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "mpool");
|
||||
_DeleteInfo(ip);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Interface doesn't currently support DB_MPOOLFILE configuration.
|
||||
*/
|
||||
if ((ret = mpf->open(mpf, file, flag, mode, (size_t)pgsize)) != 0) {
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "mpool");
|
||||
_DeleteInfo(ip);
|
||||
|
||||
(void)mpf->close(mpf, 0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Success. Set up return. Set up new info and command widget for
|
||||
* this mpool.
|
||||
*/
|
||||
envip->i_envmpid++;
|
||||
ip->i_parent = envip;
|
||||
ip->i_pgsz = pgsize;
|
||||
_SetInfoData(ip, mpf);
|
||||
(void)Tcl_CreateObjCommand(interp, newname,
|
||||
(Tcl_ObjCmdProc *)mp_Cmd, (ClientData)mpf, NULL);
|
||||
res = NewStringObj(newname, strlen(newname));
|
||||
Tcl_SetObjResult(interp, res);
|
||||
|
||||
error:
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_MpStat --
|
||||
*
|
||||
* PUBLIC: int tcl_MpStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_MpStat(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
DB_MPOOL_FSTAT **fsp, **savefsp;
|
||||
DB_MPOOL_STAT *sp;
|
||||
int result;
|
||||
int ret;
|
||||
Tcl_Obj *res;
|
||||
Tcl_Obj *res1;
|
||||
|
||||
result = TCL_OK;
|
||||
savefsp = NULL;
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbenv->memp_stat(dbenv, &sp, &fsp, 0);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "memp stat");
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
|
||||
/*
|
||||
* Have our stats, now construct the name value
|
||||
* list pairs and free up the memory.
|
||||
*/
|
||||
res = Tcl_NewObj();
|
||||
#ifdef HAVE_STATISTICS
|
||||
/*
|
||||
* MAKE_STAT_LIST assumes 'res' and 'error' label.
|
||||
*/
|
||||
MAKE_STAT_LIST("Cache size (gbytes)", sp->st_gbytes);
|
||||
MAKE_STAT_LIST("Cache size (bytes)", sp->st_bytes);
|
||||
MAKE_STAT_LIST("Number of caches", sp->st_ncache);
|
||||
MAKE_STAT_LIST("Maximum number of caches", sp->st_max_ncache);
|
||||
MAKE_STAT_LIST("Region size", sp->st_regsize);
|
||||
MAKE_STAT_LIST("Maximum memory-mapped file size", sp->st_mmapsize);
|
||||
MAKE_STAT_LIST("Maximum open file descriptors", sp->st_maxopenfd);
|
||||
MAKE_STAT_LIST("Maximum sequential buffer writes", sp->st_maxwrite);
|
||||
MAKE_STAT_LIST(
|
||||
"Sleep after writing maximum buffers", sp->st_maxwrite_sleep);
|
||||
MAKE_STAT_LIST("Pages mapped into address space", sp->st_map);
|
||||
MAKE_STAT_LIST("Cache hits", sp->st_cache_hit);
|
||||
MAKE_STAT_LIST("Cache misses", sp->st_cache_miss);
|
||||
MAKE_STAT_LIST("Pages created", sp->st_page_create);
|
||||
MAKE_STAT_LIST("Pages read in", sp->st_page_in);
|
||||
MAKE_STAT_LIST("Pages written", sp->st_page_out);
|
||||
MAKE_STAT_LIST("Clean page evictions", sp->st_ro_evict);
|
||||
MAKE_STAT_LIST("Dirty page evictions", sp->st_rw_evict);
|
||||
MAKE_STAT_LIST("Dirty pages trickled", sp->st_page_trickle);
|
||||
MAKE_STAT_LIST("Cached pages", sp->st_pages);
|
||||
MAKE_STAT_LIST("Cached clean pages", sp->st_page_clean);
|
||||
MAKE_STAT_LIST("Cached dirty pages", sp->st_page_dirty);
|
||||
MAKE_STAT_LIST("Hash buckets", sp->st_hash_buckets);
|
||||
MAKE_STAT_LIST("Hash lookups", sp->st_hash_searches);
|
||||
MAKE_STAT_LIST("Longest hash chain found", sp->st_hash_longest);
|
||||
MAKE_STAT_LIST("Hash elements examined", sp->st_hash_examined);
|
||||
MAKE_STAT_LIST("Number of hash bucket nowaits", sp->st_hash_nowait);
|
||||
MAKE_STAT_LIST("Number of hash bucket waits", sp->st_hash_wait);
|
||||
MAKE_STAT_LIST("Maximum number of hash bucket nowaits",
|
||||
sp->st_hash_max_nowait);
|
||||
MAKE_STAT_LIST("Maximum number of hash bucket waits",
|
||||
sp->st_hash_max_wait);
|
||||
MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
|
||||
MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait);
|
||||
MAKE_STAT_LIST("Buffers frozen", sp->st_mvcc_frozen);
|
||||
MAKE_STAT_LIST("Buffers thawed", sp->st_mvcc_thawed);
|
||||
MAKE_STAT_LIST("Frozen buffers freed", sp->st_mvcc_freed);
|
||||
MAKE_STAT_LIST("Page allocations", sp->st_alloc);
|
||||
MAKE_STAT_LIST("Buckets examined during allocation",
|
||||
sp->st_alloc_buckets);
|
||||
MAKE_STAT_LIST("Maximum buckets examined during allocation",
|
||||
sp->st_alloc_max_buckets);
|
||||
MAKE_STAT_LIST("Pages examined during allocation", sp->st_alloc_pages);
|
||||
MAKE_STAT_LIST("Maximum pages examined during allocation",
|
||||
sp->st_alloc_max_pages);
|
||||
MAKE_STAT_LIST("Threads waiting on buffer I/O", sp->st_io_wait);
|
||||
|
||||
/*
|
||||
* Save global stat list as res1. The MAKE_STAT_LIST
|
||||
* macro assumes 'res' so we'll use that to build up
|
||||
* our per-file sublist.
|
||||
*/
|
||||
res1 = res;
|
||||
for (savefsp = fsp; fsp != NULL && *fsp != NULL; fsp++) {
|
||||
res = Tcl_NewObj();
|
||||
result = _SetListElem(interp, res, "File Name",
|
||||
strlen("File Name"), (*fsp)->file_name,
|
||||
strlen((*fsp)->file_name));
|
||||
if (result != TCL_OK)
|
||||
goto error;
|
||||
MAKE_STAT_LIST("Page size", (*fsp)->st_pagesize);
|
||||
MAKE_STAT_LIST("Pages mapped into address space",
|
||||
(*fsp)->st_map);
|
||||
MAKE_STAT_LIST("Cache hits", (*fsp)->st_cache_hit);
|
||||
MAKE_STAT_LIST("Cache misses", (*fsp)->st_cache_miss);
|
||||
MAKE_STAT_LIST("Pages created", (*fsp)->st_page_create);
|
||||
MAKE_STAT_LIST("Pages read in", (*fsp)->st_page_in);
|
||||
MAKE_STAT_LIST("Pages written", (*fsp)->st_page_out);
|
||||
/*
|
||||
* Now that we have a complete "per-file" stat list, append
|
||||
* that to the other list.
|
||||
*/
|
||||
result = Tcl_ListObjAppendElement(interp, res1, res);
|
||||
if (result != TCL_OK)
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
Tcl_SetObjResult(interp, res1);
|
||||
error:
|
||||
__os_ufree(dbenv->env, sp);
|
||||
if (savefsp != NULL)
|
||||
__os_ufree(dbenv->env, savefsp);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* mp_Cmd --
|
||||
* Implements the "mp" widget.
|
||||
*/
|
||||
static int
|
||||
mp_Cmd(clientData, interp, objc, objv)
|
||||
ClientData clientData; /* Mp handle */
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
{
|
||||
static const char *mpcmds[] = {
|
||||
"close",
|
||||
"fsync",
|
||||
"get",
|
||||
"get_clear_len",
|
||||
"get_fileid",
|
||||
"get_ftype",
|
||||
"get_lsn_offset",
|
||||
"get_pgcookie",
|
||||
NULL
|
||||
};
|
||||
enum mpcmds {
|
||||
MPCLOSE,
|
||||
MPFSYNC,
|
||||
MPGET,
|
||||
MPGETCLEARLEN,
|
||||
MPGETFILEID,
|
||||
MPGETFTYPE,
|
||||
MPGETLSNOFFSET,
|
||||
MPGETPGCOOKIE
|
||||
};
|
||||
DB_MPOOLFILE *mp;
|
||||
int cmdindex, ftype, length, result, ret;
|
||||
DBTCL_INFO *mpip;
|
||||
Tcl_Obj *res;
|
||||
char *obj_name;
|
||||
u_int32_t value;
|
||||
int32_t intval;
|
||||
u_int8_t fileid[DB_FILE_ID_LEN];
|
||||
DBT cookie;
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
mp = (DB_MPOOLFILE *)clientData;
|
||||
obj_name = Tcl_GetStringFromObj(objv[0], &length);
|
||||
mpip = _NameToInfo(obj_name);
|
||||
result = TCL_OK;
|
||||
|
||||
if (mp == NULL) {
|
||||
Tcl_SetResult(interp, "NULL mp pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (mpip == NULL) {
|
||||
Tcl_SetResult(interp, "NULL mp info pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the dbcmds
|
||||
* defined above.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp,
|
||||
objv[1], mpcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
|
||||
return (IS_HELP(objv[1]));
|
||||
|
||||
res = NULL;
|
||||
switch ((enum mpcmds)cmdindex) {
|
||||
case MPCLOSE:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = mp->close(mp, 0);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"mp close");
|
||||
_MpInfoDelete(interp, mpip);
|
||||
(void)Tcl_DeleteCommand(interp, mpip->i_name);
|
||||
_DeleteInfo(mpip);
|
||||
break;
|
||||
case MPFSYNC:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = mp->sync(mp);
|
||||
res = Tcl_NewIntObj(ret);
|
||||
break;
|
||||
case MPGET:
|
||||
result = tcl_MpGet(interp, objc, objv, mp, mpip);
|
||||
break;
|
||||
case MPGETCLEARLEN:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
ret = mp->get_clear_len(mp, &value);
|
||||
if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"mp get_clear_len")) == TCL_OK)
|
||||
res = Tcl_NewIntObj((int)value);
|
||||
break;
|
||||
case MPGETFILEID:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
ret = mp->get_fileid(mp, fileid);
|
||||
if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"mp get_fileid")) == TCL_OK)
|
||||
res = NewStringObj((char *)fileid, DB_FILE_ID_LEN);
|
||||
break;
|
||||
case MPGETFTYPE:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
ret = mp->get_ftype(mp, &ftype);
|
||||
if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"mp get_ftype")) == TCL_OK)
|
||||
res = Tcl_NewIntObj(ftype);
|
||||
break;
|
||||
case MPGETLSNOFFSET:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
ret = mp->get_lsn_offset(mp, &intval);
|
||||
if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"mp get_lsn_offset")) == TCL_OK)
|
||||
res = Tcl_NewIntObj(intval);
|
||||
break;
|
||||
case MPGETPGCOOKIE:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
memset(&cookie, 0, sizeof(DBT));
|
||||
ret = mp->get_pgcookie(mp, &cookie);
|
||||
if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"mp get_pgcookie")) == TCL_OK)
|
||||
res = Tcl_NewByteArrayObj((u_char *)cookie.data,
|
||||
(int)cookie.size);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Only set result if we have a res. Otherwise, lower
|
||||
* functions have already done so.
|
||||
*/
|
||||
if (result == TCL_OK && res)
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_MpGet --
|
||||
*/
|
||||
static int
|
||||
tcl_MpGet(interp, objc, objv, mp, mpip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_MPOOLFILE *mp; /* mp pointer */
|
||||
DBTCL_INFO *mpip; /* mp info pointer */
|
||||
{
|
||||
static const char *mpget[] = {
|
||||
"-create",
|
||||
"-dirty",
|
||||
"-last",
|
||||
"-new",
|
||||
"-txn",
|
||||
NULL
|
||||
};
|
||||
enum mpget {
|
||||
MPGET_CREATE,
|
||||
MPGET_DIRTY,
|
||||
MPGET_LAST,
|
||||
MPGET_NEW,
|
||||
MPGET_TXN
|
||||
};
|
||||
|
||||
DBTCL_INFO *ip;
|
||||
Tcl_Obj *res;
|
||||
DB_TXN *txn;
|
||||
db_pgno_t pgno;
|
||||
u_int32_t flag;
|
||||
int i, ipgno, optindex, result, ret;
|
||||
char *arg, msg[MSG_SIZE], newname[MSG_SIZE];
|
||||
void *page;
|
||||
|
||||
txn = NULL;
|
||||
result = TCL_OK;
|
||||
memset(newname, 0, MSG_SIZE);
|
||||
i = 2;
|
||||
flag = 0;
|
||||
while (i < objc) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i],
|
||||
mpget, "option", TCL_EXACT, &optindex) != TCL_OK) {
|
||||
/*
|
||||
* Reset the result so we don't get an errant
|
||||
* error message if there is another error.
|
||||
* This arg is the page number.
|
||||
*/
|
||||
if (IS_HELP(objv[i]) == TCL_OK)
|
||||
return (TCL_OK);
|
||||
Tcl_ResetResult(interp);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
switch ((enum mpget)optindex) {
|
||||
case MPGET_CREATE:
|
||||
flag |= DB_MPOOL_CREATE;
|
||||
break;
|
||||
case MPGET_DIRTY:
|
||||
flag |= DB_MPOOL_DIRTY;
|
||||
break;
|
||||
case MPGET_LAST:
|
||||
flag |= DB_MPOOL_LAST;
|
||||
break;
|
||||
case MPGET_NEW:
|
||||
flag |= DB_MPOOL_NEW;
|
||||
break;
|
||||
case MPGET_TXN:
|
||||
if (i == objc) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
arg = Tcl_GetStringFromObj(objv[i++], NULL);
|
||||
txn = NAME_TO_TXN(arg);
|
||||
if (txn == NULL) {
|
||||
snprintf(msg, MSG_SIZE,
|
||||
"mpool get: Invalid txn: %s\n", arg);
|
||||
Tcl_SetResult(interp, msg, TCL_VOLATILE);
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (result != TCL_OK)
|
||||
goto error;
|
||||
}
|
||||
/*
|
||||
* Any left over arg is a page number. It better be the last arg.
|
||||
*/
|
||||
ipgno = 0;
|
||||
if (i != objc) {
|
||||
if (i != objc - 1) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?args? ?pgno?");
|
||||
result = TCL_ERROR;
|
||||
goto error;
|
||||
}
|
||||
result = Tcl_GetIntFromObj(interp, objv[i++], &ipgno);
|
||||
if (result != TCL_OK)
|
||||
goto error;
|
||||
}
|
||||
|
||||
snprintf(newname, sizeof(newname), "%s.pg%d",
|
||||
mpip->i_name, mpip->i_mppgid);
|
||||
ip = _NewInfo(interp, NULL, newname, I_PG);
|
||||
if (ip == NULL) {
|
||||
Tcl_SetResult(interp, "Could not set up info",
|
||||
TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
pgno = (db_pgno_t)ipgno;
|
||||
ret = mp->get(mp, &pgno, NULL, flag, &page);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_MPGET(ret), "mpool get");
|
||||
if (result == TCL_ERROR)
|
||||
_DeleteInfo(ip);
|
||||
else {
|
||||
/*
|
||||
* Success. Set up return. Set up new info
|
||||
* and command widget for this mpool.
|
||||
*/
|
||||
mpip->i_mppgid++;
|
||||
ip->i_parent = mpip;
|
||||
ip->i_pgno = pgno;
|
||||
ip->i_pgsz = mpip->i_pgsz;
|
||||
_SetInfoData(ip, page);
|
||||
(void)Tcl_CreateObjCommand(interp, newname,
|
||||
(Tcl_ObjCmdProc *)pg_Cmd, (ClientData)page, NULL);
|
||||
res = NewStringObj(newname, strlen(newname));
|
||||
Tcl_SetObjResult(interp, res);
|
||||
}
|
||||
error:
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_Cmd --
|
||||
* Implements the "pg" widget.
|
||||
*/
|
||||
static int
|
||||
pg_Cmd(clientData, interp, objc, objv)
|
||||
ClientData clientData; /* Page handle */
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
{
|
||||
static const char *pgcmds[] = {
|
||||
"init",
|
||||
"is_setto",
|
||||
"pgnum",
|
||||
"pgsize",
|
||||
"put",
|
||||
NULL
|
||||
};
|
||||
enum pgcmds {
|
||||
PGINIT,
|
||||
PGISSET,
|
||||
PGNUM,
|
||||
PGSIZE,
|
||||
PGPUT
|
||||
};
|
||||
DB_MPOOLFILE *mp;
|
||||
int cmdindex, length, result;
|
||||
char *obj_name;
|
||||
void *page;
|
||||
DBTCL_INFO *pgip;
|
||||
Tcl_Obj *res;
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
page = (void *)clientData;
|
||||
obj_name = Tcl_GetStringFromObj(objv[0], &length);
|
||||
pgip = _NameToInfo(obj_name);
|
||||
mp = NAME_TO_MP(pgip->i_parent->i_name);
|
||||
result = TCL_OK;
|
||||
|
||||
if (page == NULL) {
|
||||
Tcl_SetResult(interp, "NULL page pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (mp == NULL) {
|
||||
Tcl_SetResult(interp, "NULL mp pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (pgip == NULL) {
|
||||
Tcl_SetResult(interp, "NULL page info pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the dbcmds
|
||||
* defined above.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp,
|
||||
objv[1], pgcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
|
||||
return (IS_HELP(objv[1]));
|
||||
|
||||
res = NULL;
|
||||
switch ((enum pgcmds)cmdindex) {
|
||||
case PGNUM:
|
||||
res = Tcl_NewWideIntObj((Tcl_WideInt)pgip->i_pgno);
|
||||
break;
|
||||
case PGSIZE:
|
||||
res = Tcl_NewWideIntObj((Tcl_WideInt)pgip->i_pgsz);
|
||||
break;
|
||||
case PGPUT:
|
||||
result = tcl_Pg(interp, objc, objv, page, mp, pgip);
|
||||
break;
|
||||
case PGINIT:
|
||||
result = tcl_PgInit(interp, objc, objv, page, pgip);
|
||||
break;
|
||||
case PGISSET:
|
||||
result = tcl_PgIsset(interp, objc, objv, page, pgip);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only set result if we have a res. Otherwise, lower
|
||||
* functions have already done so.
|
||||
*/
|
||||
if (result == TCL_OK && res != NULL)
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
tcl_Pg(interp, objc, objv, page, mp, pgip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
void *page; /* Page pointer */
|
||||
DB_MPOOLFILE *mp; /* Mpool pointer */
|
||||
DBTCL_INFO *pgip; /* Info pointer */
|
||||
{
|
||||
static const char *pgopt[] = {
|
||||
"-discard",
|
||||
NULL
|
||||
};
|
||||
enum pgopt {
|
||||
PGDISCARD
|
||||
};
|
||||
u_int32_t flag;
|
||||
int i, optindex, result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
i = 2;
|
||||
flag = 0;
|
||||
while (i < objc) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i],
|
||||
pgopt, "option", TCL_EXACT, &optindex) != TCL_OK)
|
||||
return (IS_HELP(objv[i]));
|
||||
i++;
|
||||
switch ((enum pgopt)optindex) {
|
||||
case PGDISCARD:
|
||||
flag |= DB_MPOOL_DISCARD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_debug_check();
|
||||
ret = mp->put(mp, page, DB_PRIORITY_UNCHANGED, flag);
|
||||
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "page");
|
||||
|
||||
(void)Tcl_DeleteCommand(interp, pgip->i_name);
|
||||
_DeleteInfo(pgip);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
tcl_PgInit(interp, objc, objv, page, pgip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
void *page; /* Page pointer */
|
||||
DBTCL_INFO *pgip; /* Info pointer */
|
||||
{
|
||||
Tcl_Obj *res;
|
||||
long *p, *endp, newval;
|
||||
int length, pgsz, result;
|
||||
u_char *s;
|
||||
|
||||
result = TCL_OK;
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "val");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
pgsz = pgip->i_pgsz;
|
||||
result = Tcl_GetLongFromObj(interp, objv[2], &newval);
|
||||
if (result != TCL_OK) {
|
||||
s = Tcl_GetByteArrayFromObj(objv[2], &length);
|
||||
if (s == NULL)
|
||||
return (TCL_ERROR);
|
||||
memcpy(page, s, (size_t)((length < pgsz) ? length : pgsz));
|
||||
result = TCL_OK;
|
||||
} else {
|
||||
p = (long *)page;
|
||||
for (endp = p + ((u_int)pgsz / sizeof(long)); p < endp; p++)
|
||||
*p = newval;
|
||||
}
|
||||
res = Tcl_NewIntObj(0);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
tcl_PgIsset(interp, objc, objv, page, pgip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
void *page; /* Page pointer */
|
||||
DBTCL_INFO *pgip; /* Info pointer */
|
||||
{
|
||||
Tcl_Obj *res;
|
||||
long *p, *endp, newval;
|
||||
int length, pgsz, result;
|
||||
u_char *s;
|
||||
|
||||
result = TCL_OK;
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "val");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
pgsz = pgip->i_pgsz;
|
||||
result = Tcl_GetLongFromObj(interp, objv[2], &newval);
|
||||
if (result != TCL_OK) {
|
||||
if ((s = Tcl_GetByteArrayFromObj(objv[2], &length)) == NULL)
|
||||
return (TCL_ERROR);
|
||||
result = TCL_OK;
|
||||
|
||||
if (memcmp(page, s,
|
||||
(size_t)((length < pgsz) ? length : pgsz)) != 0) {
|
||||
res = Tcl_NewIntObj(0);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
} else {
|
||||
p = (long *)page;
|
||||
/*
|
||||
* If any value is not the same, return 0 (is not set to
|
||||
* this value). Otherwise, if we finish the loop, we return 1
|
||||
* (is set to this value).
|
||||
*/
|
||||
for (endp = p + ((u_int)pgsz / sizeof(long)); p < endp; p++)
|
||||
if (*p != newval) {
|
||||
res = Tcl_NewIntObj(0);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
|
||||
res = Tcl_NewIntObj(1);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
#endif
|
||||
1322
tcl/tcl_rep.c
Normal file
1322
tcl/tcl_rep.c
Normal file
File diff suppressed because it is too large
Load Diff
511
tcl/tcl_seq.c
Normal file
511
tcl/tcl_seq.c
Normal file
@@ -0,0 +1,511 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2004,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: tcl_seq.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
#ifdef HAVE_64BIT_TYPES
|
||||
|
||||
#include "db_int.h"
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#include <tcl.h>
|
||||
#endif
|
||||
#include "dbinc/tcl_db.h"
|
||||
#include "dbinc_auto/sequence_ext.h"
|
||||
|
||||
/*
|
||||
* Prototypes for procedures defined later in this file:
|
||||
*/
|
||||
static int tcl_SeqClose __P((Tcl_Interp *,
|
||||
int, Tcl_Obj * CONST*, DB_SEQUENCE *, DBTCL_INFO *));
|
||||
static int tcl_SeqGet __P((Tcl_Interp *,
|
||||
int, Tcl_Obj * CONST*, DB_SEQUENCE *));
|
||||
static int tcl_SeqRemove __P((Tcl_Interp *,
|
||||
int, Tcl_Obj * CONST*, DB_SEQUENCE *, DBTCL_INFO *));
|
||||
static int tcl_SeqStat __P((Tcl_Interp *,
|
||||
int, Tcl_Obj * CONST*, DB_SEQUENCE *));
|
||||
static int tcl_SeqGetFlags __P((Tcl_Interp *,
|
||||
int, Tcl_Obj * CONST*, DB_SEQUENCE *));
|
||||
|
||||
/*
|
||||
*
|
||||
* PUBLIC: int seq_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
|
||||
*
|
||||
* seq_Cmd --
|
||||
* Implements the "seq" widget.
|
||||
*/
|
||||
int
|
||||
seq_Cmd(clientData, interp, objc, objv)
|
||||
ClientData clientData; /* SEQ handle */
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
{
|
||||
static const char *seqcmds[] = {
|
||||
"close",
|
||||
"get",
|
||||
"get_cachesize",
|
||||
"get_db",
|
||||
"get_flags",
|
||||
"get_key",
|
||||
"get_range",
|
||||
"remove",
|
||||
"stat",
|
||||
NULL
|
||||
};
|
||||
enum seqcmds {
|
||||
SEQCLOSE,
|
||||
SEQGET,
|
||||
SEQGETCACHESIZE,
|
||||
SEQGETDB,
|
||||
SEQGETFLAGS,
|
||||
SEQGETKEY,
|
||||
SEQGETRANGE,
|
||||
SEQREMOVE,
|
||||
SEQSTAT
|
||||
};
|
||||
DB *dbp;
|
||||
DBT key;
|
||||
DBTCL_INFO *dbip, *ip;
|
||||
DB_SEQUENCE *seq;
|
||||
Tcl_Obj *myobjv[2], *res;
|
||||
db_seq_t min, max;
|
||||
int cmdindex, ncache, result, ret;
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
seq = (DB_SEQUENCE *)clientData;
|
||||
result = TCL_OK;
|
||||
dbip = NULL;
|
||||
if (objc <= 1) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (seq == NULL) {
|
||||
Tcl_SetResult(interp, "NULL sequence pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
ip = _PtrToInfo((void *)seq);
|
||||
if (ip == NULL) {
|
||||
Tcl_SetResult(interp, "NULL info pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the dbcmds
|
||||
* defined above.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp,
|
||||
objv[1], seqcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
|
||||
return (IS_HELP(objv[1]));
|
||||
|
||||
res = NULL;
|
||||
switch ((enum seqcmds)cmdindex) {
|
||||
case SEQGETRANGE:
|
||||
ret = seq->get_range(seq, &min, &max);
|
||||
if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"sequence get_range")) == TCL_OK) {
|
||||
myobjv[0] = Tcl_NewWideIntObj(min);
|
||||
myobjv[1] = Tcl_NewWideIntObj(max);
|
||||
res = Tcl_NewListObj(2, myobjv);
|
||||
}
|
||||
break;
|
||||
case SEQCLOSE:
|
||||
result = tcl_SeqClose(interp, objc, objv, seq, ip);
|
||||
break;
|
||||
case SEQREMOVE:
|
||||
result = tcl_SeqRemove(interp, objc, objv, seq, ip);
|
||||
break;
|
||||
case SEQGET:
|
||||
result = tcl_SeqGet(interp, objc, objv, seq);
|
||||
break;
|
||||
case SEQSTAT:
|
||||
result = tcl_SeqStat(interp, objc, objv, seq);
|
||||
break;
|
||||
case SEQGETCACHESIZE:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
ret = seq->get_cachesize(seq, &ncache);
|
||||
if ((result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "sequence get_cachesize")) == TCL_OK)
|
||||
res = Tcl_NewIntObj(ncache);
|
||||
break;
|
||||
case SEQGETDB:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
ret = seq->get_db(seq, &dbp);
|
||||
if (ret == 0 && (dbip = _PtrToInfo((void *)dbp)) == NULL) {
|
||||
Tcl_SetResult(interp,
|
||||
"NULL db info pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
if ((result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "sequence get_db")) == TCL_OK)
|
||||
res = NewStringObj(dbip->i_name, strlen(dbip->i_name));
|
||||
break;
|
||||
case SEQGETKEY:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
ret = seq->get_key(seq, &key);
|
||||
if ((result = _ReturnSetup(interp, ret,
|
||||
DB_RETOK_STD(ret), "sequence get_key")) == TCL_OK)
|
||||
res = Tcl_NewByteArrayObj(
|
||||
(u_char *)key.data, (int)key.size);
|
||||
break;
|
||||
case SEQGETFLAGS:
|
||||
result = tcl_SeqGetFlags(interp, objc, objv, seq);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only set result if we have a res. Otherwise, lower functions have
|
||||
* already done so.
|
||||
*/
|
||||
if (result == TCL_OK && res)
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_db_stat --
|
||||
*/
|
||||
static int
|
||||
tcl_SeqStat(interp, objc, objv, seq)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_SEQUENCE *seq; /* Database pointer */
|
||||
{
|
||||
DB_SEQUENCE_STAT *sp;
|
||||
u_int32_t flag;
|
||||
Tcl_Obj *res, *flaglist, *myobjv[2];
|
||||
int result, ret;
|
||||
char *arg;
|
||||
|
||||
result = TCL_OK;
|
||||
flag = 0;
|
||||
|
||||
if (objc > 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-clear?");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
if (objc == 3) {
|
||||
arg = Tcl_GetStringFromObj(objv[2], NULL);
|
||||
if (strcmp(arg, "-clear") == 0)
|
||||
flag = DB_STAT_CLEAR;
|
||||
else {
|
||||
Tcl_SetResult(interp,
|
||||
"db stat: unknown arg", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
_debug_check();
|
||||
ret = seq->stat(seq, &sp, flag);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db stat");
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
|
||||
res = Tcl_NewObj();
|
||||
MAKE_STAT_LIST("Wait", sp->st_wait);
|
||||
MAKE_STAT_LIST("No wait", sp->st_nowait);
|
||||
MAKE_WSTAT_LIST("Current", sp->st_current);
|
||||
MAKE_WSTAT_LIST("Cached", sp->st_value);
|
||||
MAKE_WSTAT_LIST("Max Cached", sp->st_last_value);
|
||||
MAKE_WSTAT_LIST("Min", sp->st_min);
|
||||
MAKE_WSTAT_LIST("Max", sp->st_max);
|
||||
MAKE_STAT_LIST("Cache size", sp->st_cache_size);
|
||||
/*
|
||||
* Construct a {name {flag1 flag2 ... flagN}} list for the
|
||||
* seq flags.
|
||||
*/
|
||||
myobjv[0] = NewStringObj("Flags", strlen("Flags"));
|
||||
myobjv[1] =
|
||||
_GetFlagsList(interp, sp->st_flags, __db_get_seq_flags_fn());
|
||||
flaglist = Tcl_NewListObj(2, myobjv);
|
||||
if (flaglist == NULL) {
|
||||
result = TCL_ERROR;
|
||||
goto error;
|
||||
}
|
||||
if ((result =
|
||||
Tcl_ListObjAppendElement(interp, res, flaglist)) != TCL_OK)
|
||||
goto error;
|
||||
|
||||
Tcl_SetObjResult(interp, res);
|
||||
|
||||
error: __os_ufree(seq->seq_dbp->env, sp);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_db_close --
|
||||
*/
|
||||
static int
|
||||
tcl_SeqClose(interp, objc, objv, seq, ip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_SEQUENCE *seq; /* Database pointer */
|
||||
DBTCL_INFO *ip; /* Info pointer */
|
||||
{
|
||||
int result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
if (objc > 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
_DeleteInfo(ip);
|
||||
_debug_check();
|
||||
|
||||
ret = seq->close(seq, 0);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "sequence close");
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_SeqGet --
|
||||
*/
|
||||
static int
|
||||
tcl_SeqGet(interp, objc, objv, seq)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_SEQUENCE *seq; /* Sequence pointer */
|
||||
{
|
||||
static const char *seqgetopts[] = {
|
||||
"-nosync",
|
||||
"-txn",
|
||||
NULL
|
||||
};
|
||||
enum seqgetopts {
|
||||
SEQGET_NOSYNC,
|
||||
SEQGET_TXN
|
||||
};
|
||||
DB_TXN *txn;
|
||||
Tcl_Obj *res;
|
||||
db_seq_t value;
|
||||
u_int32_t aflag, delta;
|
||||
int i, end, optindex, result, ret;
|
||||
char *arg, msg[MSG_SIZE];
|
||||
|
||||
result = TCL_OK;
|
||||
txn = NULL;
|
||||
aflag = 0;
|
||||
|
||||
if (objc < 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-args? delta");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the options
|
||||
* defined above.
|
||||
*/
|
||||
i = 2;
|
||||
end = objc;
|
||||
while (i < end) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i], seqgetopts, "option",
|
||||
TCL_EXACT, &optindex) != TCL_OK) {
|
||||
arg = Tcl_GetStringFromObj(objv[i], NULL);
|
||||
if (arg[0] == '-') {
|
||||
result = IS_HELP(objv[i]);
|
||||
goto out;
|
||||
} else
|
||||
Tcl_ResetResult(interp);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
switch ((enum seqgetopts)optindex) {
|
||||
case SEQGET_NOSYNC:
|
||||
aflag |= DB_TXN_NOSYNC;
|
||||
break;
|
||||
case SEQGET_TXN:
|
||||
if (i >= end) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
arg = Tcl_GetStringFromObj(objv[i++], NULL);
|
||||
txn = NAME_TO_TXN(arg);
|
||||
if (txn == NULL) {
|
||||
snprintf(msg, MSG_SIZE,
|
||||
"Get: Invalid txn: %s\n", arg);
|
||||
Tcl_SetResult(interp, msg, TCL_VOLATILE);
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
} /* switch */
|
||||
if (result != TCL_OK)
|
||||
break;
|
||||
}
|
||||
if (result != TCL_OK)
|
||||
goto out;
|
||||
|
||||
if (i != objc - 1) {
|
||||
Tcl_SetResult(interp,
|
||||
"Wrong number of key/data given\n", TCL_STATIC);
|
||||
result = TCL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((result = _GetUInt32(interp, objv[objc - 1], &delta)) != TCL_OK)
|
||||
goto out;
|
||||
|
||||
ret = seq->get(seq, txn, (int32_t)delta, &value, aflag);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_DBGET(ret), "sequence get");
|
||||
if (ret == 0) {
|
||||
res = Tcl_NewWideIntObj((Tcl_WideInt)value);
|
||||
Tcl_SetObjResult(interp, res);
|
||||
}
|
||||
out:
|
||||
return (result);
|
||||
}
|
||||
/*
|
||||
*/
|
||||
static int
|
||||
tcl_SeqRemove(interp, objc, objv, seq, ip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_SEQUENCE *seq; /* Sequence pointer */
|
||||
DBTCL_INFO *ip; /* Info pointer */
|
||||
{
|
||||
static const char *seqgetopts[] = {
|
||||
"-nosync",
|
||||
"-txn",
|
||||
NULL
|
||||
};
|
||||
enum seqgetopts {
|
||||
SEQGET_NOSYNC,
|
||||
SEQGET_TXN
|
||||
};
|
||||
DB_TXN *txn;
|
||||
u_int32_t aflag;
|
||||
int i, end, optindex, result, ret;
|
||||
char *arg, msg[MSG_SIZE];
|
||||
|
||||
result = TCL_OK;
|
||||
txn = NULL;
|
||||
aflag = 0;
|
||||
|
||||
_DeleteInfo(ip);
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-args?");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the options
|
||||
* defined above.
|
||||
*/
|
||||
i = 2;
|
||||
end = objc;
|
||||
while (i < end) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i], seqgetopts, "option",
|
||||
TCL_EXACT, &optindex) != TCL_OK) {
|
||||
arg = Tcl_GetStringFromObj(objv[i], NULL);
|
||||
if (arg[0] == '-') {
|
||||
result = IS_HELP(objv[i]);
|
||||
goto out;
|
||||
} else
|
||||
Tcl_ResetResult(interp);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
switch ((enum seqgetopts)optindex) {
|
||||
case SEQGET_NOSYNC:
|
||||
aflag |= DB_TXN_NOSYNC;
|
||||
break;
|
||||
case SEQGET_TXN:
|
||||
if (i >= end) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
arg = Tcl_GetStringFromObj(objv[i++], NULL);
|
||||
txn = NAME_TO_TXN(arg);
|
||||
if (txn == NULL) {
|
||||
snprintf(msg, MSG_SIZE,
|
||||
"Remove: Invalid txn: %s\n", arg);
|
||||
Tcl_SetResult(interp, msg, TCL_VOLATILE);
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
} /* switch */
|
||||
if (result != TCL_OK)
|
||||
break;
|
||||
}
|
||||
if (result != TCL_OK)
|
||||
goto out;
|
||||
|
||||
ret = seq->remove(seq, txn, aflag);
|
||||
result = _ReturnSetup(interp,
|
||||
ret, DB_RETOK_DBGET(ret), "sequence remove");
|
||||
out:
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_SeqGetFlags --
|
||||
*/
|
||||
static int
|
||||
tcl_SeqGetFlags(interp, objc, objv, seq)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_SEQUENCE *seq; /* Sequence pointer */
|
||||
{
|
||||
int i, ret, result;
|
||||
u_int32_t flags;
|
||||
char buf[512];
|
||||
Tcl_Obj *res;
|
||||
|
||||
static const struct {
|
||||
u_int32_t flag;
|
||||
char *arg;
|
||||
} seq_flags[] = {
|
||||
{ DB_SEQ_INC, "-inc" },
|
||||
{ DB_SEQ_DEC, "-dec" },
|
||||
{ DB_SEQ_WRAP, "-wrap" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
ret = seq->get_flags(seq, &flags);
|
||||
if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"db get_flags")) == TCL_OK) {
|
||||
buf[0] = '\0';
|
||||
|
||||
for (i = 0; seq_flags[i].flag != 0; i++)
|
||||
if (LF_ISSET(seq_flags[i].flag)) {
|
||||
if (strlen(buf) > 0)
|
||||
(void)strncat(buf, " ", sizeof(buf));
|
||||
(void)strncat(
|
||||
buf, seq_flags[i].arg, sizeof(buf));
|
||||
}
|
||||
|
||||
res = NewStringObj(buf, strlen(buf));
|
||||
Tcl_SetObjResult(interp, res);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
#endif /* HAVE_64BIT_TYPES */
|
||||
778
tcl/tcl_txn.c
Normal file
778
tcl/tcl_txn.c
Normal file
@@ -0,0 +1,778 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1999,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: tcl_txn.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#include <tcl.h>
|
||||
#endif
|
||||
#include "dbinc/tcl_db.h"
|
||||
|
||||
static int tcl_TxnCommit __P((Tcl_Interp *,
|
||||
int, Tcl_Obj * CONST *, DB_TXN *, DBTCL_INFO *));
|
||||
static int txn_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST *));
|
||||
|
||||
/*
|
||||
* _TxnInfoDelete --
|
||||
* Removes nested txn info structures that are children
|
||||
* of this txn.
|
||||
* RECURSIVE: Transactions can be arbitrarily nested, so we
|
||||
* must recurse down until we get them all.
|
||||
*
|
||||
* PUBLIC: void _TxnInfoDelete __P((Tcl_Interp *, DBTCL_INFO *));
|
||||
*/
|
||||
void
|
||||
_TxnInfoDelete(interp, txnip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
DBTCL_INFO *txnip; /* Info for txn */
|
||||
{
|
||||
DBTCL_INFO *nextp, *p;
|
||||
|
||||
for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) {
|
||||
/*
|
||||
* Check if this info structure "belongs" to this
|
||||
* txn. Remove its commands and info structure.
|
||||
*/
|
||||
nextp = LIST_NEXT(p, entries);
|
||||
if (p->i_parent == txnip && p->i_type == I_TXN) {
|
||||
_TxnInfoDelete(interp, p);
|
||||
(void)Tcl_DeleteCommand(interp, p->i_name);
|
||||
_DeleteInfo(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_TxnCheckpoint --
|
||||
*
|
||||
* PUBLIC: int tcl_TxnCheckpoint __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_TxnCheckpoint(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
static const char *txnckpopts[] = {
|
||||
"-force",
|
||||
"-kbyte",
|
||||
"-min",
|
||||
NULL
|
||||
};
|
||||
enum txnckpopts {
|
||||
TXNCKP_FORCE,
|
||||
TXNCKP_KB,
|
||||
TXNCKP_MIN
|
||||
};
|
||||
u_int32_t flags;
|
||||
int i, kb, min, optindex, result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
flags = 0;
|
||||
kb = min = 0;
|
||||
|
||||
/*
|
||||
* Get the flag index from the object based on the options
|
||||
* defined above.
|
||||
*/
|
||||
i = 2;
|
||||
while (i < objc) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i],
|
||||
txnckpopts, "option", TCL_EXACT, &optindex) != TCL_OK) {
|
||||
return (IS_HELP(objv[i]));
|
||||
}
|
||||
i++;
|
||||
switch ((enum txnckpopts)optindex) {
|
||||
case TXNCKP_FORCE:
|
||||
flags = DB_FORCE;
|
||||
break;
|
||||
case TXNCKP_KB:
|
||||
if (i == objc) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"?-kbyte kb?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
result = Tcl_GetIntFromObj(interp, objv[i++], &kb);
|
||||
break;
|
||||
case TXNCKP_MIN:
|
||||
if (i == objc) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?-min min?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
result = Tcl_GetIntFromObj(interp, objv[i++], &min);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbenv->txn_checkpoint(dbenv, (u_int32_t)kb, (u_int32_t)min,
|
||||
flags);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"txn checkpoint");
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_Txn --
|
||||
*
|
||||
* PUBLIC: int tcl_Txn __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *));
|
||||
*/
|
||||
int
|
||||
tcl_Txn(interp, objc, objv, dbenv, envip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
DBTCL_INFO *envip; /* Info pointer */
|
||||
{
|
||||
static const char *txnopts[] = {
|
||||
#ifdef CONFIG_TEST
|
||||
"-lock_timeout",
|
||||
"-read_committed",
|
||||
"-read_uncommitted",
|
||||
"-txn_timeout",
|
||||
"-txn_wait",
|
||||
#endif
|
||||
"-nosync",
|
||||
"-nowait",
|
||||
"-parent",
|
||||
"-snapshot",
|
||||
"-sync",
|
||||
"-wrnosync",
|
||||
NULL
|
||||
};
|
||||
enum txnopts {
|
||||
#ifdef CONFIG_TEST
|
||||
TXNLOCK_TIMEOUT,
|
||||
TXNREAD_COMMITTED,
|
||||
TXNREAD_UNCOMMITTED,
|
||||
TXNTIMEOUT,
|
||||
TXNWAIT,
|
||||
#endif
|
||||
TXNNOSYNC,
|
||||
TXNNOWAIT,
|
||||
TXNPARENT,
|
||||
TXNSNAPSHOT,
|
||||
TXNSYNC,
|
||||
TXNWRNOSYNC
|
||||
};
|
||||
DBTCL_INFO *ip;
|
||||
DB_TXN *parent;
|
||||
DB_TXN *txn;
|
||||
Tcl_Obj *res;
|
||||
u_int32_t flag;
|
||||
int i, optindex, result, ret;
|
||||
char *arg, msg[MSG_SIZE], newname[MSG_SIZE];
|
||||
#ifdef CONFIG_TEST
|
||||
db_timeout_t lk_time, tx_time;
|
||||
u_int32_t lk_timeflag, tx_timeflag;
|
||||
#endif
|
||||
|
||||
result = TCL_OK;
|
||||
memset(newname, 0, MSG_SIZE);
|
||||
|
||||
parent = NULL;
|
||||
flag = 0;
|
||||
#ifdef CONFIG_TEST
|
||||
COMPQUIET(tx_time, 0);
|
||||
COMPQUIET(lk_time, 0);
|
||||
lk_timeflag = tx_timeflag = 0;
|
||||
#endif
|
||||
i = 2;
|
||||
while (i < objc) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i],
|
||||
txnopts, "option", TCL_EXACT, &optindex) != TCL_OK) {
|
||||
return (IS_HELP(objv[i]));
|
||||
}
|
||||
i++;
|
||||
switch ((enum txnopts)optindex) {
|
||||
#ifdef CONFIG_TEST
|
||||
case TXNLOCK_TIMEOUT:
|
||||
lk_timeflag = DB_SET_LOCK_TIMEOUT;
|
||||
goto get_timeout;
|
||||
case TXNTIMEOUT:
|
||||
tx_timeflag = DB_SET_TXN_TIMEOUT;
|
||||
get_timeout: if (i >= objc) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"?-txn_timestamp time?");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
result = Tcl_GetLongFromObj(interp, objv[i++], (long *)
|
||||
((enum txnopts)optindex == TXNLOCK_TIMEOUT ?
|
||||
&lk_time : &tx_time));
|
||||
if (result != TCL_OK)
|
||||
return (TCL_ERROR);
|
||||
break;
|
||||
case TXNREAD_COMMITTED:
|
||||
flag |= DB_READ_COMMITTED;
|
||||
break;
|
||||
case TXNREAD_UNCOMMITTED:
|
||||
flag |= DB_READ_UNCOMMITTED;
|
||||
break;
|
||||
case TXNWAIT:
|
||||
flag |= DB_TXN_WAIT;
|
||||
break;
|
||||
#endif
|
||||
case TXNNOSYNC:
|
||||
flag |= DB_TXN_NOSYNC;
|
||||
break;
|
||||
case TXNNOWAIT:
|
||||
flag |= DB_TXN_NOWAIT;
|
||||
break;
|
||||
case TXNPARENT:
|
||||
if (i == objc) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"?-parent txn?");
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
arg = Tcl_GetStringFromObj(objv[i++], NULL);
|
||||
parent = NAME_TO_TXN(arg);
|
||||
if (parent == NULL) {
|
||||
snprintf(msg, MSG_SIZE,
|
||||
"Invalid parent txn: %s\n",
|
||||
arg);
|
||||
Tcl_SetResult(interp, msg, TCL_VOLATILE);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
break;
|
||||
case TXNSNAPSHOT:
|
||||
flag |= DB_TXN_SNAPSHOT;
|
||||
break;
|
||||
case TXNSYNC:
|
||||
flag |= DB_TXN_SYNC;
|
||||
break;
|
||||
case TXNWRNOSYNC:
|
||||
flag |= DB_TXN_WRITE_NOSYNC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
snprintf(newname, sizeof(newname), "%s.txn%d",
|
||||
envip->i_name, envip->i_envtxnid);
|
||||
ip = _NewInfo(interp, NULL, newname, I_TXN);
|
||||
if (ip == NULL) {
|
||||
Tcl_SetResult(interp, "Could not set up info",
|
||||
TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbenv->txn_begin(dbenv, parent, &txn, flag);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"txn");
|
||||
if (result == TCL_ERROR)
|
||||
_DeleteInfo(ip);
|
||||
else {
|
||||
/*
|
||||
* Success. Set up return. Set up new info
|
||||
* and command widget for this txn.
|
||||
*/
|
||||
envip->i_envtxnid++;
|
||||
if (parent)
|
||||
ip->i_parent = _PtrToInfo(parent);
|
||||
else
|
||||
ip->i_parent = envip;
|
||||
_SetInfoData(ip, txn);
|
||||
(void)Tcl_CreateObjCommand(interp, newname,
|
||||
(Tcl_ObjCmdProc *)txn_Cmd, (ClientData)txn, NULL);
|
||||
res = NewStringObj(newname, strlen(newname));
|
||||
Tcl_SetObjResult(interp, res);
|
||||
#ifdef CONFIG_TEST
|
||||
if (tx_timeflag != 0) {
|
||||
ret = txn->set_timeout(txn, tx_time, tx_timeflag);
|
||||
if (ret != 0) {
|
||||
result =
|
||||
_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"set_timeout");
|
||||
_DeleteInfo(ip);
|
||||
}
|
||||
}
|
||||
if (lk_timeflag != 0) {
|
||||
ret = txn->set_timeout(txn, lk_time, lk_timeflag);
|
||||
if (ret != 0) {
|
||||
result =
|
||||
_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"set_timeout");
|
||||
_DeleteInfo(ip);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_CDSGroup --
|
||||
*
|
||||
* PUBLIC: int tcl_CDSGroup __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *));
|
||||
*/
|
||||
int
|
||||
tcl_CDSGroup(interp, objc, objv, dbenv, envip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
DBTCL_INFO *envip; /* Info pointer */
|
||||
{
|
||||
DBTCL_INFO *ip;
|
||||
DB_TXN *txn;
|
||||
Tcl_Obj *res;
|
||||
int result, ret;
|
||||
char newname[MSG_SIZE];
|
||||
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "env cdsgroup");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
result = TCL_OK;
|
||||
memset(newname, 0, MSG_SIZE);
|
||||
|
||||
snprintf(newname, sizeof(newname), "%s.txn%d",
|
||||
envip->i_name, envip->i_envtxnid);
|
||||
ip = _NewInfo(interp, NULL, newname, I_TXN);
|
||||
if (ip == NULL) {
|
||||
Tcl_SetResult(interp, "Could not set up info",
|
||||
TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbenv->cdsgroup_begin(dbenv, &txn);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "cdsgroup");
|
||||
if (result == TCL_ERROR)
|
||||
_DeleteInfo(ip);
|
||||
else {
|
||||
/*
|
||||
* Success. Set up return. Set up new info
|
||||
* and command widget for this txn.
|
||||
*/
|
||||
envip->i_envtxnid++;
|
||||
ip->i_parent = envip;
|
||||
_SetInfoData(ip, txn);
|
||||
(void)Tcl_CreateObjCommand(interp, newname,
|
||||
(Tcl_ObjCmdProc *)txn_Cmd, (ClientData)txn, NULL);
|
||||
res = NewStringObj(newname, strlen(newname));
|
||||
Tcl_SetObjResult(interp, res);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_TxnStat --
|
||||
*
|
||||
* PUBLIC: int tcl_TxnStat __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_TxnStat(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
DBTCL_INFO *ip;
|
||||
DB_TXN_ACTIVE *p;
|
||||
DB_TXN_STAT *sp;
|
||||
Tcl_Obj *myobjv[2], *res, *thislist, *lsnlist;
|
||||
u_int32_t i;
|
||||
int myobjc, result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbenv->txn_stat(dbenv, &sp, 0);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"txn stat");
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
|
||||
/*
|
||||
* Have our stats, now construct the name value
|
||||
* list pairs and free up the memory.
|
||||
*/
|
||||
res = Tcl_NewObj();
|
||||
/*
|
||||
* MAKE_STAT_LIST assumes 'res' and 'error' label.
|
||||
*/
|
||||
#ifdef HAVE_STATISTICS
|
||||
MAKE_STAT_LIST("Region size", sp->st_regsize);
|
||||
MAKE_STAT_LSN("LSN of last checkpoint", &sp->st_last_ckp);
|
||||
MAKE_STAT_LIST("Time of last checkpoint", sp->st_time_ckp);
|
||||
MAKE_STAT_LIST("Last txn ID allocated", sp->st_last_txnid);
|
||||
MAKE_STAT_LIST("Maximum txns", sp->st_maxtxns);
|
||||
MAKE_STAT_LIST("Number aborted txns", sp->st_naborts);
|
||||
MAKE_STAT_LIST("Number txns begun", sp->st_nbegins);
|
||||
MAKE_STAT_LIST("Number committed txns", sp->st_ncommits);
|
||||
MAKE_STAT_LIST("Number active txns", sp->st_nactive);
|
||||
MAKE_STAT_LIST("Number of snapshot txns", sp->st_nsnapshot);
|
||||
MAKE_STAT_LIST("Number restored txns", sp->st_nrestores);
|
||||
MAKE_STAT_LIST("Maximum active txns", sp->st_maxnactive);
|
||||
MAKE_STAT_LIST("Maximum snapshot txns", sp->st_maxnsnapshot);
|
||||
MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait);
|
||||
MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
|
||||
for (i = 0, p = sp->st_txnarray; i < sp->st_nactive; i++, p++)
|
||||
LIST_FOREACH(ip, &__db_infohead, entries) {
|
||||
if (ip->i_type != I_TXN)
|
||||
continue;
|
||||
if (ip->i_type == I_TXN &&
|
||||
(ip->i_txnp->id(ip->i_txnp) == p->txnid)) {
|
||||
MAKE_STAT_LSN(ip->i_name, &p->lsn);
|
||||
if (p->parentid != 0)
|
||||
MAKE_STAT_STRLIST("Parent",
|
||||
ip->i_parent->i_name);
|
||||
else
|
||||
MAKE_STAT_LIST("Parent", 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Tcl_SetObjResult(interp, res);
|
||||
error:
|
||||
__os_ufree(dbenv->env, sp);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* tcl_TxnTimeout --
|
||||
*
|
||||
* PUBLIC: int tcl_TxnTimeout __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
|
||||
*/
|
||||
int
|
||||
tcl_TxnTimeout(interp, objc, objv, dbenv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
{
|
||||
long timeout;
|
||||
int result, ret;
|
||||
|
||||
/*
|
||||
* One arg, the timeout.
|
||||
*/
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?timeout?");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
result = Tcl_GetLongFromObj(interp, objv[2], &timeout);
|
||||
if (result != TCL_OK)
|
||||
return (result);
|
||||
_debug_check();
|
||||
ret = dbenv->set_timeout(dbenv, (u_int32_t)timeout, DB_SET_TXN_TIMEOUT);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"lock timeout");
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* txn_Cmd --
|
||||
* Implements the "txn" widget.
|
||||
*/
|
||||
static int
|
||||
txn_Cmd(clientData, interp, objc, objv)
|
||||
ClientData clientData; /* Txn handle */
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
{
|
||||
static const char *txncmds[] = {
|
||||
#ifdef CONFIG_TEST
|
||||
"discard",
|
||||
"getname",
|
||||
"id",
|
||||
"prepare",
|
||||
"setname",
|
||||
#endif
|
||||
"abort",
|
||||
"commit",
|
||||
"getname",
|
||||
"setname",
|
||||
NULL
|
||||
};
|
||||
enum txncmds {
|
||||
#ifdef CONFIG_TEST
|
||||
TXNDISCARD,
|
||||
TXNGETNAME,
|
||||
TXNID,
|
||||
TXNPREPARE,
|
||||
TXNSETNAME,
|
||||
#endif
|
||||
TXNABORT,
|
||||
TXNCOMMIT
|
||||
};
|
||||
DBTCL_INFO *txnip;
|
||||
DB_TXN *txnp;
|
||||
Tcl_Obj *res;
|
||||
int cmdindex, result, ret;
|
||||
#ifdef CONFIG_TEST
|
||||
u_int8_t *gid, garray[DB_XIDDATASIZE];
|
||||
int length;
|
||||
const char *name;
|
||||
#endif
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
txnp = (DB_TXN *)clientData;
|
||||
txnip = _PtrToInfo((void *)txnp);
|
||||
result = TCL_OK;
|
||||
if (txnp == NULL) {
|
||||
Tcl_SetResult(interp, "NULL txn pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (txnip == NULL) {
|
||||
Tcl_SetResult(interp, "NULL txn info pointer", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command name index from the object based on the dbcmds
|
||||
* defined above.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp,
|
||||
objv[1], txncmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
|
||||
return (IS_HELP(objv[1]));
|
||||
|
||||
res = NULL;
|
||||
switch ((enum txncmds)cmdindex) {
|
||||
#ifdef CONFIG_TEST
|
||||
case TXNDISCARD:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = txnp->discard(txnp, 0);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"txn discard");
|
||||
_TxnInfoDelete(interp, txnip);
|
||||
(void)Tcl_DeleteCommand(interp, txnip->i_name);
|
||||
_DeleteInfo(txnip);
|
||||
break;
|
||||
case TXNID:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
res = Tcl_NewIntObj((int)txnp->id(txnp));
|
||||
break;
|
||||
case TXNPREPARE:
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
gid = (u_int8_t *)Tcl_GetByteArrayFromObj(objv[2], &length);
|
||||
memcpy(garray, gid, (size_t)length);
|
||||
ret = txnp->prepare(txnp, garray);
|
||||
/*
|
||||
* !!!
|
||||
* DB_TXN->prepare commits all outstanding children. But it
|
||||
* does NOT destroy the current txn handle. So, we must call
|
||||
* _TxnInfoDelete to recursively remove all nested txn handles,
|
||||
* we do not call _DeleteInfo on ourselves.
|
||||
*/
|
||||
_TxnInfoDelete(interp, txnip);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"txn prepare");
|
||||
break;
|
||||
case TXNGETNAME:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = txnp->get_name(txnp, &name);
|
||||
if ((result = _ReturnSetup(
|
||||
interp, ret, DB_RETOK_STD(ret), "txn getname")) == TCL_OK)
|
||||
res = NewStringObj(name, strlen(name));
|
||||
break;
|
||||
case TXNSETNAME:
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "name");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = txnp->set_name(txnp, Tcl_GetStringFromObj(objv[2], NULL));
|
||||
result =
|
||||
_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "setname");
|
||||
break;
|
||||
#endif
|
||||
case TXNABORT:
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = txnp->abort(txnp);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"txn abort");
|
||||
_TxnInfoDelete(interp, txnip);
|
||||
(void)Tcl_DeleteCommand(interp, txnip->i_name);
|
||||
_DeleteInfo(txnip);
|
||||
break;
|
||||
case TXNCOMMIT:
|
||||
result = tcl_TxnCommit(interp, objc, objv, txnp, txnip);
|
||||
_TxnInfoDelete(interp, txnip);
|
||||
(void)Tcl_DeleteCommand(interp, txnip->i_name);
|
||||
_DeleteInfo(txnip);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Only set result if we have a res. Otherwise, lower
|
||||
* functions have already done so.
|
||||
*/
|
||||
if (result == TCL_OK && res)
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
tcl_TxnCommit(interp, objc, objv, txnp, txnip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_TXN *txnp; /* Transaction pointer */
|
||||
DBTCL_INFO *txnip; /* Info pointer */
|
||||
{
|
||||
static const char *commitopt[] = {
|
||||
"-nosync",
|
||||
"-sync",
|
||||
"-wrnosync",
|
||||
NULL
|
||||
};
|
||||
enum commitopt {
|
||||
COMNOSYNC,
|
||||
COMSYNC,
|
||||
COMWRNOSYNC
|
||||
};
|
||||
u_int32_t flag;
|
||||
int optindex, result, ret;
|
||||
|
||||
COMPQUIET(txnip, NULL);
|
||||
|
||||
result = TCL_OK;
|
||||
flag = 0;
|
||||
if (objc != 2 && objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (objc == 3) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[2], commitopt,
|
||||
"option", TCL_EXACT, &optindex) != TCL_OK)
|
||||
return (IS_HELP(objv[2]));
|
||||
switch ((enum commitopt)optindex) {
|
||||
case COMSYNC:
|
||||
flag = DB_TXN_SYNC;
|
||||
break;
|
||||
case COMNOSYNC:
|
||||
flag = DB_TXN_NOSYNC;
|
||||
break;
|
||||
case COMWRNOSYNC:
|
||||
flag = DB_TXN_WRITE_NOSYNC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_debug_check();
|
||||
ret = txnp->commit(txnp, flag);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"txn commit");
|
||||
return (result);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TEST
|
||||
/*
|
||||
* tcl_TxnRecover --
|
||||
*
|
||||
* PUBLIC: int tcl_TxnRecover __P((Tcl_Interp *, int,
|
||||
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *));
|
||||
*/
|
||||
int
|
||||
tcl_TxnRecover(interp, objc, objv, dbenv, envip)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
DB_ENV *dbenv; /* Environment pointer */
|
||||
DBTCL_INFO *envip; /* Info pointer */
|
||||
{
|
||||
#define DO_PREPLIST(count) \
|
||||
for (i = 0; i < count; i++) { \
|
||||
snprintf(newname, sizeof(newname), "%s.txn%d", \
|
||||
envip->i_name, envip->i_envtxnid); \
|
||||
ip = _NewInfo(interp, NULL, newname, I_TXN); \
|
||||
if (ip == NULL) { \
|
||||
Tcl_SetResult(interp, "Could not set up info", \
|
||||
TCL_STATIC); \
|
||||
return (TCL_ERROR); \
|
||||
} \
|
||||
envip->i_envtxnid++; \
|
||||
ip->i_parent = envip; \
|
||||
p = &prep[i]; \
|
||||
_SetInfoData(ip, p->txn); \
|
||||
(void)Tcl_CreateObjCommand(interp, newname, \
|
||||
(Tcl_ObjCmdProc *)txn_Cmd, (ClientData)p->txn, NULL); \
|
||||
result = _SetListElem(interp, res, newname, strlen(newname), \
|
||||
p->gid, DB_XIDDATASIZE); \
|
||||
if (result != TCL_OK) \
|
||||
goto error; \
|
||||
}
|
||||
|
||||
DBTCL_INFO *ip;
|
||||
DB_PREPLIST prep[DBTCL_PREP], *p;
|
||||
Tcl_Obj *res;
|
||||
long count, i;
|
||||
int result, ret;
|
||||
char newname[MSG_SIZE];
|
||||
|
||||
result = TCL_OK;
|
||||
/*
|
||||
* No args for this. Error if there are some.
|
||||
*/
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
_debug_check();
|
||||
ret = dbenv->txn_recover(dbenv, prep, DBTCL_PREP, &count, DB_FIRST);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"txn recover");
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
res = Tcl_NewObj();
|
||||
DO_PREPLIST(count);
|
||||
|
||||
/*
|
||||
* If count returned is the maximum size we have, then there
|
||||
* might be more. Keep going until we get them all.
|
||||
*/
|
||||
while (count == DBTCL_PREP) {
|
||||
ret = dbenv->txn_recover(
|
||||
dbenv, prep, DBTCL_PREP, &count, DB_NEXT);
|
||||
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
|
||||
"txn recover");
|
||||
if (result == TCL_ERROR)
|
||||
return (result);
|
||||
DO_PREPLIST(count);
|
||||
}
|
||||
Tcl_SetObjResult(interp, res);
|
||||
error:
|
||||
return (result);
|
||||
}
|
||||
#endif
|
||||
109
tcl/tcl_util.c
Normal file
109
tcl/tcl_util.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1999,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: tcl_util.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#include <tcl.h>
|
||||
#endif
|
||||
#include "dbinc/tcl_db.h"
|
||||
|
||||
/*
|
||||
* bdb_RandCommand --
|
||||
* Implements rand* functions.
|
||||
*
|
||||
* PUBLIC: int bdb_RandCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
|
||||
*/
|
||||
int
|
||||
bdb_RandCommand(interp, objc, objv)
|
||||
Tcl_Interp *interp; /* Interpreter */
|
||||
int objc; /* How many arguments? */
|
||||
Tcl_Obj *CONST objv[]; /* The argument objects */
|
||||
{
|
||||
static const char *rcmds[] = {
|
||||
"rand", "random_int", "srand",
|
||||
NULL
|
||||
};
|
||||
enum rcmds {
|
||||
RRAND, RRAND_INT, RSRAND
|
||||
};
|
||||
Tcl_Obj *res;
|
||||
int cmdindex, hi, lo, result, ret;
|
||||
|
||||
result = TCL_OK;
|
||||
/*
|
||||
* Get the command name index from the object based on the cmds
|
||||
* defined above. This SHOULD NOT fail because we already checked
|
||||
* in the 'berkdb' command.
|
||||
*/
|
||||
if (Tcl_GetIndexFromObj(interp,
|
||||
objv[1], rcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
|
||||
return (IS_HELP(objv[1]));
|
||||
|
||||
res = NULL;
|
||||
switch ((enum rcmds)cmdindex) {
|
||||
case RRAND:
|
||||
/*
|
||||
* Must be 0 args. Error if different.
|
||||
*/
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, NULL);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
ret = rand();
|
||||
res = Tcl_NewIntObj(ret);
|
||||
break;
|
||||
case RRAND_INT:
|
||||
/*
|
||||
* Must be 4 args. Error if different.
|
||||
*/
|
||||
if (objc != 4) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "lo hi");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if ((result =
|
||||
Tcl_GetIntFromObj(interp, objv[2], &lo)) != TCL_OK)
|
||||
return (result);
|
||||
if ((result =
|
||||
Tcl_GetIntFromObj(interp, objv[3], &hi)) != TCL_OK)
|
||||
return (result);
|
||||
if (lo < 0 || hi < 0) {
|
||||
Tcl_SetResult(interp,
|
||||
"Range value less than 0", TCL_STATIC);
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
|
||||
_debug_check();
|
||||
ret = lo + rand() % ((hi - lo) + 1);
|
||||
res = Tcl_NewIntObj(ret);
|
||||
break;
|
||||
case RSRAND:
|
||||
/*
|
||||
* Must be 1 arg. Error if different.
|
||||
*/
|
||||
if (objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "seed");
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if ((result =
|
||||
Tcl_GetIntFromObj(interp, objv[2], &lo)) == TCL_OK) {
|
||||
srand((u_int)lo);
|
||||
res = Tcl_NewIntObj(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only set result if we have a res. Otherwise, lower functions have
|
||||
* already done so.
|
||||
*/
|
||||
if (result == TCL_OK && res)
|
||||
Tcl_SetObjResult(interp, res);
|
||||
return (result);
|
||||
}
|
||||
Reference in New Issue
Block a user