mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19: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
|
/* Run a select for the search given by (DESC,NDESC). The data is not
|
||||||
* returned but stored in the request item. */
|
* returned but stored in the request item. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
@ -1000,6 +1036,16 @@ be_sqlite_search (ctrl_t ctrl,
|
|||||||
goto leave;
|
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:
|
again:
|
||||||
if (!ctx->select_done)
|
if (!ctx->select_done)
|
||||||
{
|
{
|
||||||
@ -1395,9 +1441,14 @@ be_sqlite_store (ctrl_t ctrl, backend_handle_t backend_hd,
|
|||||||
goto leave;
|
goto leave;
|
||||||
/* ctx = part->besqlite; */
|
/* ctx = part->besqlite; */
|
||||||
|
|
||||||
err = run_sql_statement ("begin transaction");
|
if (!opt.active_transaction)
|
||||||
if (err)
|
{
|
||||||
goto leave;
|
err = run_sql_statement ("begin transaction");
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
if (opt.in_transaction)
|
||||||
|
opt.active_transaction = 1;
|
||||||
|
}
|
||||||
in_transaction = 1;
|
in_transaction = 1;
|
||||||
|
|
||||||
err = store_into_pubkey (mode, pktype, ubid, blob, bloblen);
|
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:
|
leave:
|
||||||
if (in_transaction && !err)
|
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)
|
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");
|
log_error ("Warning: database rollback failed - should not happen!\n");
|
||||||
}
|
}
|
||||||
if (got_mutex)
|
if (got_mutex)
|
||||||
@ -1586,9 +1644,14 @@ be_sqlite_delete (ctrl_t ctrl, backend_handle_t backend_hd,
|
|||||||
goto leave;
|
goto leave;
|
||||||
/* ctx = part->besqlite; */
|
/* ctx = part->besqlite; */
|
||||||
|
|
||||||
err = run_sql_statement ("begin transaction");
|
if (!opt.active_transaction)
|
||||||
if (err)
|
{
|
||||||
goto leave;
|
err = run_sql_statement ("begin transaction");
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
if (opt.in_transaction)
|
||||||
|
opt.active_transaction = 1;
|
||||||
|
}
|
||||||
in_transaction = 1;
|
in_transaction = 1;
|
||||||
|
|
||||||
err = run_sql_statement_bind_ubid
|
err = run_sql_statement_bind_ubid
|
||||||
@ -1607,11 +1670,19 @@ be_sqlite_delete (ctrl_t ctrl, backend_handle_t backend_hd,
|
|||||||
leave:
|
leave:
|
||||||
if (stmt)
|
if (stmt)
|
||||||
sqlite3_finalize (stmt);
|
sqlite3_finalize (stmt);
|
||||||
|
|
||||||
if (in_transaction && !err)
|
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)
|
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");
|
log_error ("Warning: database rollback failed - should not happen!\n");
|
||||||
}
|
}
|
||||||
release_mutex ();
|
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,
|
gpg_error_t be_sqlite_init_local (backend_handle_t backend_hd,
|
||||||
db_request_part_t part);
|
db_request_part_t part);
|
||||||
void be_sqlite_release_local (be_sqlite_local_t ctx);
|
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,
|
gpg_error_t be_sqlite_search (ctrl_t ctrl, backend_handle_t hd,
|
||||||
db_request_t request,
|
db_request_t request,
|
||||||
KEYDB_SEARCH_DESC *desc, unsigned int ndesc);
|
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
|
/* Search for the keys described by (DESC,NDESC) and return them to
|
||||||
* the caller. If RESET is set, the search state is first reset.
|
* 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);
|
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,
|
gpg_error_t kbxd_search (ctrl_t ctrl,
|
||||||
KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
|
KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
|
||||||
int reset);
|
int reset);
|
||||||
|
120
kbx/kbxserver.c
120
kbx/kbxserver.c
@ -50,6 +50,13 @@
|
|||||||
/* Control structure per connection. */
|
/* Control structure per connection. */
|
||||||
struct server_local_s
|
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 */
|
/* Data used to associate an Assuan context with local server data */
|
||||||
assuan_context_t assuan_ctx;
|
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. */
|
/* 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[] =
|
static const char hlp_getinfo[] =
|
||||||
"GETINFO <what>\n"
|
"GETINFO <what>\n"
|
||||||
@ -689,6 +771,7 @@ register_commands (assuan_context_t ctx)
|
|||||||
{ "NEXT", cmd_next, hlp_next },
|
{ "NEXT", cmd_next, hlp_next },
|
||||||
{ "STORE", cmd_store, hlp_store },
|
{ "STORE", cmd_store, hlp_store },
|
||||||
{ "DELETE", cmd_delete, hlp_delete },
|
{ "DELETE", cmd_delete, hlp_delete },
|
||||||
|
{ "TRANSACTION",cmd_transaction,hlp_transaction },
|
||||||
{ "GETINFO", cmd_getinfo, hlp_getinfo },
|
{ "GETINFO", cmd_getinfo, hlp_getinfo },
|
||||||
{ "OUTPUT", NULL, hlp_output },
|
{ "OUTPUT", NULL, hlp_output },
|
||||||
{ "KILLKEYBOXD",cmd_killkeyboxd,hlp_killkeyboxd },
|
{ "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);
|
xfree (ctrl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ctrl->server_local->client_pid = ASSUAN_INVALID_PID;
|
||||||
|
|
||||||
rc = assuan_new (&ctx);
|
rc = assuan_new (&ctx);
|
||||||
if (rc)
|
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;
|
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. */
|
/* The next call enable the use of status_printf. */
|
||||||
set_assuan_context_func (get_assuan_ctx_from_ctrl);
|
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);
|
(long)peercred->gid);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
ctrl->server_local->client_pid = assuan_get_pid (ctx);
|
||||||
|
|
||||||
rc = assuan_process (ctx);
|
rc = assuan_process (ctx);
|
||||||
if (rc)
|
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);
|
assuan_close_output_fd (ctx);
|
||||||
|
|
||||||
set_assuan_context_func (NULL);
|
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);
|
ctrl->refcount);
|
||||||
else
|
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->multi_search_desc);
|
||||||
xfree (ctrl->server_local);
|
xfree (ctrl->server_local);
|
||||||
ctrl->server_local = NULL;
|
ctrl->server_local = NULL;
|
||||||
|
@ -45,6 +45,15 @@ struct
|
|||||||
/* True if we are running detached from the tty. */
|
/* True if we are running detached from the tty. */
|
||||||
int running_detached;
|
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;
|
} opt;
|
||||||
|
|
||||||
|
|
||||||
@ -118,6 +127,7 @@ struct server_control_s
|
|||||||
unsigned int filter_x509 : 1;
|
unsigned int filter_x509 : 1;
|
||||||
/* Used by SEARCH and NEXT. */
|
/* Used by SEARCH and NEXT. */
|
||||||
unsigned int no_data_return : 1;
|
unsigned int no_data_return : 1;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user