mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-21 10:09:57 +01:00
keyboxd: New command TRANSACTION.
* kbx/backend-sqlite.c (be_sqlite_rollback): New. (be_sqlite_commit): New. (be_sqlite_search): Take care of global transactions. (be_sqlite_store): Ditto. (be_sqlite_delete): Ditto. * kbx/frontend.c (kbxd_rollback, kbxd_commit): New. * kbx/keyboxd.h (opt): Add vars for transactions. * kbx/kbxserver.c (struct server_local_s): Add fields next_session and client_pid. (session_list): New var. (cmd_transaction): New. (register_commands): Register command. (kbxd_start_command_handler): Store pids and track sessions. Do a final rollback. -- This command is currently an experiment to allow a client to run everything in one session. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
b19a60c6f7
commit
c2b14f5d68
@ -681,6 +681,42 @@ be_sqlite_release_local (be_sqlite_local_t ctx)
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
be_sqlite_rollback (void)
|
||||
{
|
||||
opt.in_transaction = 0;
|
||||
if (!opt.active_transaction)
|
||||
return 0; /* Nothing to do. */
|
||||
|
||||
if (!database_hd)
|
||||
{
|
||||
log_error ("Warning: No database handle for global rollback\n");
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
}
|
||||
|
||||
opt.active_transaction = 0;
|
||||
return run_sql_statement ("rollback");
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
be_sqlite_commit (void)
|
||||
{
|
||||
opt.in_transaction = 0;
|
||||
if (!opt.active_transaction)
|
||||
return 0; /* Nothing to do. */
|
||||
|
||||
if (!database_hd)
|
||||
{
|
||||
log_error ("Warning: No database handle for global commit\n");
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
}
|
||||
|
||||
opt.active_transaction = 0;
|
||||
return run_sql_statement ("commit");
|
||||
}
|
||||
|
||||
|
||||
/* Run a select for the search given by (DESC,NDESC). The data is not
|
||||
* returned but stored in the request item. */
|
||||
static gpg_error_t
|
||||
@ -1000,6 +1036,16 @@ be_sqlite_search (ctrl_t ctrl,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Start a global transaction if needed. */
|
||||
if (!opt.active_transaction && opt.in_transaction)
|
||||
{
|
||||
err = run_sql_statement ("begin transaction");
|
||||
if (err)
|
||||
goto leave;
|
||||
opt.active_transaction = 1;
|
||||
}
|
||||
|
||||
|
||||
again:
|
||||
if (!ctx->select_done)
|
||||
{
|
||||
@ -1395,9 +1441,14 @@ be_sqlite_store (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||
goto leave;
|
||||
/* ctx = part->besqlite; */
|
||||
|
||||
err = run_sql_statement ("begin transaction");
|
||||
if (err)
|
||||
goto leave;
|
||||
if (!opt.active_transaction)
|
||||
{
|
||||
err = run_sql_statement ("begin transaction");
|
||||
if (err)
|
||||
goto leave;
|
||||
if (opt.in_transaction)
|
||||
opt.active_transaction = 1;
|
||||
}
|
||||
in_transaction = 1;
|
||||
|
||||
err = store_into_pubkey (mode, pktype, ubid, blob, bloblen);
|
||||
@ -1541,10 +1592,17 @@ be_sqlite_store (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||
|
||||
leave:
|
||||
if (in_transaction && !err)
|
||||
err = run_sql_statement ("commit");
|
||||
{
|
||||
if (opt.active_transaction)
|
||||
; /* We are in a global transaction. */
|
||||
else
|
||||
err = run_sql_statement ("commit");
|
||||
}
|
||||
else if (in_transaction)
|
||||
{
|
||||
if (run_sql_statement ("rollback"))
|
||||
if (opt.active_transaction)
|
||||
; /* We are in a global transaction. */
|
||||
else if (run_sql_statement ("rollback"))
|
||||
log_error ("Warning: database rollback failed - should not happen!\n");
|
||||
}
|
||||
if (got_mutex)
|
||||
@ -1586,9 +1644,14 @@ be_sqlite_delete (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||
goto leave;
|
||||
/* ctx = part->besqlite; */
|
||||
|
||||
err = run_sql_statement ("begin transaction");
|
||||
if (err)
|
||||
goto leave;
|
||||
if (!opt.active_transaction)
|
||||
{
|
||||
err = run_sql_statement ("begin transaction");
|
||||
if (err)
|
||||
goto leave;
|
||||
if (opt.in_transaction)
|
||||
opt.active_transaction = 1;
|
||||
}
|
||||
in_transaction = 1;
|
||||
|
||||
err = run_sql_statement_bind_ubid
|
||||
@ -1607,11 +1670,19 @@ be_sqlite_delete (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||
leave:
|
||||
if (stmt)
|
||||
sqlite3_finalize (stmt);
|
||||
|
||||
if (in_transaction && !err)
|
||||
err = run_sql_statement ("commit");
|
||||
{
|
||||
if (opt.active_transaction)
|
||||
; /* We are in a global transaction. */
|
||||
else
|
||||
err = run_sql_statement ("commit");
|
||||
}
|
||||
else if (in_transaction)
|
||||
{
|
||||
if (run_sql_statement ("rollback"))
|
||||
if (opt.active_transaction)
|
||||
; /* We are in a global transaction. */
|
||||
else if (run_sql_statement ("rollback"))
|
||||
log_error ("Warning: database rollback failed - should not happen!\n");
|
||||
}
|
||||
release_mutex ();
|
||||
|
@ -171,6 +171,8 @@ void be_sqlite_release_resource (ctrl_t ctrl, backend_handle_t hd);
|
||||
gpg_error_t be_sqlite_init_local (backend_handle_t backend_hd,
|
||||
db_request_part_t part);
|
||||
void be_sqlite_release_local (be_sqlite_local_t ctx);
|
||||
gpg_error_t be_sqlite_rollback (void);
|
||||
gpg_error_t be_sqlite_commit (void);
|
||||
gpg_error_t be_sqlite_search (ctrl_t ctrl, backend_handle_t hd,
|
||||
db_request_t request,
|
||||
KEYDB_SEARCH_DESC *desc, unsigned int ndesc);
|
||||
|
@ -172,6 +172,21 @@ kbxd_release_session_info (ctrl_t ctrl)
|
||||
}
|
||||
|
||||
|
||||
|
||||
gpg_error_t
|
||||
kbxd_rollback (void)
|
||||
{
|
||||
return be_sqlite_rollback ();
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
kbxd_commit (void)
|
||||
{
|
||||
return be_sqlite_commit ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Search for the keys described by (DESC,NDESC) and return them to
|
||||
* the caller. If RESET is set, the search state is first reset.
|
||||
|
@ -28,6 +28,8 @@ gpg_error_t kbxd_set_database (ctrl_t ctrl,
|
||||
|
||||
void kbxd_release_session_info (ctrl_t ctrl);
|
||||
|
||||
gpg_error_t kbxd_rollback (void);
|
||||
gpg_error_t kbxd_commit (void);
|
||||
gpg_error_t kbxd_search (ctrl_t ctrl,
|
||||
KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
|
||||
int reset);
|
||||
|
120
kbx/kbxserver.c
120
kbx/kbxserver.c
@ -50,6 +50,13 @@
|
||||
/* Control structure per connection. */
|
||||
struct server_local_s
|
||||
{
|
||||
/* We keep a list of all active sessions with the anchor at
|
||||
* SESSION_LIST (see below). This field is used for linking. */
|
||||
struct server_local_s *next_session;
|
||||
|
||||
/* The pid of the client. */
|
||||
pid_t client_pid;
|
||||
|
||||
/* Data used to associate an Assuan context with local server data */
|
||||
assuan_context_t assuan_ctx;
|
||||
|
||||
@ -89,6 +96,12 @@ struct server_local_s
|
||||
};
|
||||
|
||||
|
||||
/* To keep track of all running sessions, we link all active server
|
||||
* contexts and anchor them at this variable. */
|
||||
static struct server_local_s *session_list;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Return the assuan contxt from the local server info in CTRL. */
|
||||
@ -568,6 +581,75 @@ cmd_delete (assuan_context_t ctx, char *line)
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char hlp_transaction[] =
|
||||
"TRANSACTION [begin|commit|rollback]\n"
|
||||
"\n"
|
||||
"For bulk import of data it is often useful to run everything\n"
|
||||
"in one transaction. This can be achieved with this command.\n"
|
||||
"If the last connection of client is closed before a commit\n"
|
||||
"or rollback an implicit rollback is done. With no argument\n"
|
||||
"the status of the current transaction is returned.";
|
||||
static gpg_error_t
|
||||
cmd_transaction (assuan_context_t ctx, char *line)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
|
||||
line = skip_options (line);
|
||||
|
||||
if (!strcmp (line, "begin"))
|
||||
{
|
||||
/* Note that we delay the actual transaction until we have to
|
||||
* use SQL. */
|
||||
if (opt.in_transaction)
|
||||
err = set_error (GPG_ERR_CONFLICT, "already in a transaction");
|
||||
else
|
||||
{
|
||||
opt.in_transaction = 1;
|
||||
opt.transaction_pid = assuan_get_pid (ctx);
|
||||
}
|
||||
}
|
||||
else if (!strcmp (line, "commit"))
|
||||
{
|
||||
if (!opt.in_transaction)
|
||||
err = set_error (GPG_ERR_CONFLICT, "not in a transaction");
|
||||
else if (opt.transaction_pid != assuan_get_pid (ctx))
|
||||
err = set_error (GPG_ERR_CONFLICT, "other client is in a transaction");
|
||||
else
|
||||
err = kbxd_commit ();
|
||||
}
|
||||
else if (!strcmp (line, "rollback"))
|
||||
{
|
||||
if (!opt.in_transaction)
|
||||
err = set_error (GPG_ERR_CONFLICT, "not in a transaction");
|
||||
else if (opt.transaction_pid != assuan_get_pid (ctx))
|
||||
err = set_error (GPG_ERR_CONFLICT, "other client is in a transaction");
|
||||
else
|
||||
err = kbxd_rollback ();
|
||||
}
|
||||
else if (!*line)
|
||||
{
|
||||
if (opt.in_transaction && opt.transaction_pid == assuan_get_pid (ctx))
|
||||
err = assuan_set_okay_line (ctx, opt.active_transaction?
|
||||
"active transaction" :
|
||||
"pending transaction");
|
||||
else if (opt.in_transaction)
|
||||
err = assuan_set_okay_line (ctx, opt.active_transaction?
|
||||
"active transaction on other client" :
|
||||
"pending transaction on other client");
|
||||
else
|
||||
err = set_error (GPG_ERR_FALSE, "no transaction");
|
||||
}
|
||||
else
|
||||
{
|
||||
err = set_error (GPG_ERR_ASS_PARAMETER, "unknown transaction command");
|
||||
}
|
||||
|
||||
|
||||
return leave_cmd (ctx, err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char hlp_getinfo[] =
|
||||
"GETINFO <what>\n"
|
||||
@ -689,6 +771,7 @@ register_commands (assuan_context_t ctx)
|
||||
{ "NEXT", cmd_next, hlp_next },
|
||||
{ "STORE", cmd_store, hlp_store },
|
||||
{ "DELETE", cmd_delete, hlp_delete },
|
||||
{ "TRANSACTION",cmd_transaction,hlp_transaction },
|
||||
{ "GETINFO", cmd_getinfo, hlp_getinfo },
|
||||
{ "OUTPUT", NULL, hlp_output },
|
||||
{ "KILLKEYBOXD",cmd_killkeyboxd,hlp_killkeyboxd },
|
||||
@ -764,6 +847,7 @@ kbxd_start_command_handler (ctrl_t ctrl, gnupg_fd_t fd, unsigned int session_id)
|
||||
xfree (ctrl);
|
||||
return;
|
||||
}
|
||||
ctrl->server_local->client_pid = ASSUAN_INVALID_PID;
|
||||
|
||||
rc = assuan_new (&ctx);
|
||||
if (rc)
|
||||
@ -825,6 +909,11 @@ kbxd_start_command_handler (ctrl_t ctrl, gnupg_fd_t fd, unsigned int session_id)
|
||||
|
||||
ctrl->server_local->session_id = session_id;
|
||||
|
||||
/* Put the session int a list. */
|
||||
ctrl->server_local->next_session = session_list;
|
||||
session_list = ctrl->server_local;
|
||||
|
||||
|
||||
/* The next call enable the use of status_printf. */
|
||||
set_assuan_context_func (get_assuan_ctx_from_ctrl);
|
||||
|
||||
@ -850,6 +939,7 @@ kbxd_start_command_handler (ctrl_t ctrl, gnupg_fd_t fd, unsigned int session_id)
|
||||
(long)peercred->gid);
|
||||
}
|
||||
#endif
|
||||
ctrl->server_local->client_pid = assuan_get_pid (ctx);
|
||||
|
||||
rc = assuan_process (ctx);
|
||||
if (rc)
|
||||
@ -859,6 +949,22 @@ kbxd_start_command_handler (ctrl_t ctrl, gnupg_fd_t fd, unsigned int session_id)
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.in_transaction
|
||||
&& opt.transaction_pid == ctrl->server_local->client_pid)
|
||||
{
|
||||
struct server_local_s *sl;
|
||||
pid_t thispid = ctrl->server_local->client_pid;
|
||||
int npids = 0;
|
||||
|
||||
/* Only if this is the last connection rollback the transaction. */
|
||||
for (sl = session_list; sl; sl = sl->next_session)
|
||||
if (sl->client_pid == thispid)
|
||||
npids++;
|
||||
|
||||
if (npids == 1)
|
||||
kbxd_rollback ();
|
||||
}
|
||||
|
||||
assuan_close_output_fd (ctx);
|
||||
|
||||
set_assuan_context_func (NULL);
|
||||
@ -873,6 +979,20 @@ kbxd_start_command_handler (ctrl_t ctrl, gnupg_fd_t fd, unsigned int session_id)
|
||||
ctrl->refcount);
|
||||
else
|
||||
{
|
||||
if (session_list == ctrl->server_local)
|
||||
session_list = ctrl->server_local->next_session;
|
||||
else
|
||||
{
|
||||
struct server_local_s *sl;
|
||||
|
||||
for (sl=session_list; sl->next_session; sl = sl->next_session)
|
||||
if (sl->next_session == ctrl->server_local)
|
||||
break;
|
||||
if (!sl->next_session)
|
||||
BUG ();
|
||||
sl->next_session = ctrl->server_local->next_session;
|
||||
}
|
||||
|
||||
xfree (ctrl->server_local->multi_search_desc);
|
||||
xfree (ctrl->server_local);
|
||||
ctrl->server_local = NULL;
|
||||
|
@ -45,6 +45,15 @@ struct
|
||||
/* True if we are running detached from the tty. */
|
||||
int running_detached;
|
||||
|
||||
/*
|
||||
* Global state variables.
|
||||
*/
|
||||
|
||||
/* Whether a global transaction has been requested along with the
|
||||
* caller's pid and whether a transaction is active. */
|
||||
pid_t transaction_pid;
|
||||
unsigned int in_transaction : 1;
|
||||
unsigned int active_transaction : 1;
|
||||
} opt;
|
||||
|
||||
|
||||
@ -118,6 +127,7 @@ struct server_control_s
|
||||
unsigned int filter_x509 : 1;
|
||||
/* Used by SEARCH and NEXT. */
|
||||
unsigned int no_data_return : 1;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user