diff options
author | Nathan Kinder <nkinder@redhat.com> | 2008-04-03 16:52:47 +0000 |
---|---|---|
committer | Nathan Kinder <nkinder@redhat.com> | 2008-04-03 16:52:47 +0000 |
commit | 58b91ec4cb2b7b4ede0b9cb48bf54c1ca9c34d78 (patch) | |
tree | 9883a74eb0aa1d22f3a80eca26bd55325242eb7e /ldap/servers/slapd | |
parent | 49bca93614ca0705d226630288ff8cc73df86674 (diff) | |
download | ds-58b91ec4cb2b7b4ede0b9cb48bf54c1ca9c34d78.tar.gz ds-58b91ec4cb2b7b4ede0b9cb48bf54c1ca9c34d78.tar.xz ds-58b91ec4cb2b7b4ede0b9cb48bf54c1ca9c34d78.zip |
Resolves: 439907
Summary: Enhanced SLAPI task API and ported existing tasks to use new API.
Diffstat (limited to 'ldap/servers/slapd')
-rw-r--r-- | ldap/servers/slapd/back-ldbm/archive.c | 4 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/back-ldbm.h | 6 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/dblayer.c | 6 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/import.c | 52 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/ldif2ldbm.c | 20 | ||||
-rw-r--r-- | ldap/servers/slapd/main.c | 14 | ||||
-rw-r--r-- | ldap/servers/slapd/slap.h | 25 | ||||
-rw-r--r-- | ldap/servers/slapd/slapi-plugin.h | 37 | ||||
-rw-r--r-- | ldap/servers/slapd/slapi-private.h | 40 | ||||
-rw-r--r-- | ldap/servers/slapd/task.c | 749 | ||||
-rw-r--r-- | ldap/servers/slapd/test-plugins/sampletask.c | 115 |
11 files changed, 583 insertions, 485 deletions
diff --git a/ldap/servers/slapd/back-ldbm/archive.c b/ldap/servers/slapd/back-ldbm/archive.c index be2c4c63..a0568b7a 100644 --- a/ldap/servers/slapd/back-ldbm/archive.c +++ b/ldap/servers/slapd/back-ldbm/archive.c @@ -61,7 +61,7 @@ int ldbm_back_archive2ldbm( Slapi_PBlock *pb ) slapi_pblock_get( pb, SLAPI_BACKEND_INSTANCE_NAME, &backendname); slapi_pblock_get( pb, SLAPI_BACKEND_TASK, &task ); slapi_pblock_get( pb, SLAPI_TASK_FLAGS, &task_flags ); - li->li_flags = run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE); + li->li_flags = run_from_cmdline = (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE); if ( !rawdirectory || !*rawdirectory ) { LDAPDebug( LDAP_DEBUG_ANY, "archive2db: no archive name\n", @@ -273,7 +273,7 @@ int ldbm_back_ldbm2archive( Slapi_PBlock *pb ) slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li ); slapi_pblock_get( pb, SLAPI_SEQ_VAL, &rawdirectory ); slapi_pblock_get( pb, SLAPI_TASK_FLAGS, &task_flags ); - li->li_flags = run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE); + li->li_flags = run_from_cmdline = (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE); slapi_pblock_get( pb, SLAPI_BACKEND_TASK, &task ); diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h index 87e04683..2af305fe 100644 --- a/ldap/servers/slapd/back-ldbm/back-ldbm.h +++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h @@ -513,10 +513,10 @@ struct ldbminfo { int li_legacy_errcode; /* 615428 -- in case legacy err code is expected */ }; -/* li_flags could store these bits defined in ../slap.h +/* li_flags could store these bits defined in ../slapi-plugin.h * task flag (pb_task_flags) * - * #define TASK_RUNNING_AS_TASK 0x0 - * #define TASK_RUNNING_FROM_COMMANDLINE 0x1 + * SLAPI_TASK_RUNNING_AS_TASK + * SLAPI_TASK_RUNNING_FROM_COMMANDLINE */ /* allow conf w/o CONFIG_FLAG_ALLOW_RUNNING_CHANGE to be updated */ #define LI_FORCE_MOD_CONFIG 0x10 diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c index 8f0bc07b..abd71b85 100644 --- a/ldap/servers/slapd/back-ldbm/dblayer.c +++ b/ldap/servers/slapd/back-ldbm/dblayer.c @@ -1954,7 +1954,7 @@ int dblayer_instance_start(backend *be, int mode) oflags |= DB_PRIVATE; } PR_Lock(li->li_config_mutex); - if ((li->li_flags & TASK_RUNNING_FROM_COMMANDLINE) && + if ((li->li_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE) && (li->li_import_cache_autosize)) /* Autosizing importCache * Need to re-eval every time * to guarantee the memory is @@ -5678,7 +5678,7 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task, char * * dse_conf_verify may need to have db started, as well. */ /* If no logfiles were stored, then fatal recovery isn't required */ - if (li->li_flags & TASK_RUNNING_FROM_COMMANDLINE) + if (li->li_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE) { /* command line mode; no need to run db threads */ dbmode |= DBLAYER_NO_DBTHREADS_MODE; @@ -5707,7 +5707,7 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task, char * "Warning: Unable to verify the index configuration\n", 0, 0, 0); } - if (li->li_flags & TASK_RUNNING_FROM_COMMANDLINE) { + if (li->li_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE) { /* command line: close the database down again */ tmp_rval = dblayer_close(li, dbmode); if (0 != tmp_rval) { diff --git a/ldap/servers/slapd/back-ldbm/import.c b/ldap/servers/slapd/back-ldbm/import.c index 7666dcfe..533a61c3 100644 --- a/ldap/servers/slapd/back-ldbm/import.c +++ b/ldap/servers/slapd/back-ldbm/import.c @@ -197,29 +197,19 @@ void import_log_notice(ImportJob *job, char *format, ...) buffer, 0); } -static int import_task_destroy(Slapi_Task *task) +static void import_task_destroy(Slapi_Task *task) { - ImportJob *job = (ImportJob *)task->task_private; - - if (task->task_log) { - slapi_ch_free((void **)&task->task_log); - } - - if (task->task_status) { - slapi_ch_free((void **)&task->task_status); - } - + ImportJob *job = (ImportJob *)slapi_task_get_data(task); if (job && job->task_status) { slapi_ch_free((void **)&job->task_status); job->task_status = NULL; } FREE(job); - task->task_private = NULL; - return 0; + slapi_task_set_data(task, NULL); } -static int import_task_abort(Slapi_Task *task) +static void import_task_abort(Slapi_Task *task) { ImportJob *job; @@ -227,9 +217,8 @@ static int import_task_abort(Slapi_Task *task) * DSE lock for modify... */ - if (task->task_state == SLAPI_TASK_FINISHED) { + if (slapi_task_get_state(task) == SLAPI_TASK_FINISHED) { /* too late */ - return 0; } /* @@ -238,14 +227,12 @@ static int import_task_abort(Slapi_Task *task) * because it will free the job. */ - job = (ImportJob *)task->task_private; + job = (ImportJob *)slapi_task_get_data(task); import_abort_all(job, 0); - while (task->task_state != SLAPI_TASK_FINISHED) + while (slapi_task_get_state(task) != SLAPI_TASK_FINISHED) DS_Sleep(PR_MillisecondsToInterval(100)); - - return 0; } @@ -1042,13 +1029,8 @@ static int import_all_done(ImportJob *job, int ret) slapi_ch_free_string(&inst_dirp); } - if (job->task != NULL && 0 == job->task->task_refcount) { - /* exit code */ - job->task->task_exitcode = ret; - job->task->task_state = SLAPI_TASK_FINISHED; - job->task->task_progress = job->task->task_work; - job->task->task_private = NULL; - slapi_task_status_changed(job->task); + if ((job->task != NULL) && (0 == slapi_task_get_refcount(job->task))) { + slapi_task_finish(job->task, ret); } if (job->flags & FLAG_ONLINE) { @@ -1093,7 +1075,7 @@ int import_main_offline(void *arg) ImportWorkerInfo *producer = NULL; if (job->task) - job->task->task_refcount++; + slapi_task_inc_refcount(job->task); PR_ASSERT(inst != NULL); time(&beginning); @@ -1364,13 +1346,11 @@ error: if (0 != ret) { import_log_notice(job, "Import failed."); if (job->task != NULL) { - job->task->task_state = SLAPI_TASK_FINISHED; - job->task->task_exitcode = ret; - slapi_task_status_changed(job->task); + slapi_task_finish(job->task, ret); } } else { if (job->task) - job->task->task_refcount--; + slapi_task_dec_refcount(job->task); import_all_done(job, ret); } @@ -1471,15 +1451,17 @@ int ldbm_back_ldif2ldbm_deluxe(Slapi_PBlock *pb) /* add 1 to account for post-import cleanup (which can take a * significant amount of time) */ + /* NGK - This should eventually be cleaned up to use the public + * task API. */ if (0 == total_files) /* reindexing */ job->task->task_work = 2; else job->task->task_work = total_files + 1; job->task->task_progress = 0; job->task->task_state = SLAPI_TASK_RUNNING; - job->task->task_private = job; - job->task->destructor = import_task_destroy; - job->task->cancel = import_task_abort; + slapi_task_set_data(job->task, job); + slapi_task_set_destructor_fn(job->task, import_task_destroy); + slapi_task_set_cancel_fn(job->task, import_task_abort); job->flags |= FLAG_ONLINE; /* create thread for import_main, so we can return */ diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c index 827e471c..e4f82b2f 100644 --- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c +++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c @@ -568,7 +568,7 @@ int ldbm_back_ldif2ldbm( Slapi_PBlock *pb ) /* hopefully this will go away once import is not run standalone... */ slapi_pblock_get(pb, SLAPI_TASK_FLAGS, &task_flags); - if (task_flags & TASK_RUNNING_FROM_COMMANDLINE) { + if (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE) { /* initialize UniqueID generator - must be done once backends are started and event queue is initialized but before plugins are started */ Slapi_DN *sdn = slapi_sdn_new_dn_byval ("cn=uniqueid generator,cn=config"); @@ -581,7 +581,7 @@ int ldbm_back_ldif2ldbm( Slapi_PBlock *pb ) return -1; } - li->li_flags |= TASK_RUNNING_FROM_COMMANDLINE; + li->li_flags |= SLAPI_TASK_RUNNING_FROM_COMMANDLINE; ldbm_config_load_dse_info(li); autosize_import_cache(li); } @@ -604,7 +604,7 @@ int ldbm_back_ldif2ldbm( Slapi_PBlock *pb ) /***** prepare & init libdb and dblayer *****/ - if (! (task_flags & TASK_RUNNING_FROM_COMMANDLINE)) { + if (! (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE)) { /* shutdown this instance of the db */ LDAPDebug(LDAP_DEBUG_ANY, "Bringing %s offline...\n", instance_name, 0, 0); @@ -778,11 +778,11 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb ) slapi_pblock_get( pb, SLAPI_TASK_FLAGS, &task_flags ); slapi_pblock_get( pb, SLAPI_DB2LDIF_DECRYPT, &decrypt ); slapi_pblock_get( pb, SLAPI_DB2LDIF_SERVER_RUNNING, &server_running ); - run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE); + run_from_cmdline = (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE); dump_replica = pb->pb_ldif_dump_replica; if (run_from_cmdline) { - li->li_flags |= TASK_RUNNING_FROM_COMMANDLINE; + li->li_flags |= SLAPI_TASK_RUNNING_FROM_COMMANDLINE; if (!dump_replica) { we_start_the_backends = 1; } @@ -1298,12 +1298,12 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb) slapi_pblock_get(pb, SLAPI_BACKEND_INSTANCE_NAME, &instance_name); slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &li); slapi_pblock_get(pb, SLAPI_TASK_FLAGS, &task_flags); - run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE); + run_from_cmdline = (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE); slapi_pblock_get(pb, SLAPI_BACKEND_TASK, &task); if (run_from_cmdline) { /* No ldbm backend exists until we process the config info. */ - li->li_flags |= TASK_RUNNING_FROM_COMMANDLINE; + li->li_flags |= SLAPI_TASK_RUNNING_FROM_COMMANDLINE; ldbm_config_load_dse_info(li); txn.back_txn_txn = NULL; /* no transaction */ } @@ -1764,6 +1764,8 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb) percent = (ep->ep_id*100 / (lastid ? lastid : 1)); } if (task) { + /* NGK - This should eventually be cleaned up to use the + * public task API */ task->task_progress = (idl ? idindex : ep->ep_id); task->task_work = (idl ? idl->b_nids : lastid); slapi_task_status_changed(task); @@ -1970,7 +1972,7 @@ int ldbm_back_upgradedb(Slapi_PBlock *pb) slapi_pblock_get(pb, SLAPI_BACKEND_TASK, &task); slapi_pblock_get(pb, SLAPI_DB2LDIF_SERVER_RUNNING, &server_running); - run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE); + run_from_cmdline = (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE); slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &li); if (run_from_cmdline) { @@ -2435,7 +2437,7 @@ void upgradedb_core(Slapi_PBlock *pb, ldbm_instance *inst) int run_from_cmdline = 0; slapi_pblock_get(pb, SLAPI_TASK_FLAGS, &task_flags); - run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE); + run_from_cmdline = (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE); be = inst->inst_be; slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB", diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c index 0b5f3e7d..1c1943a6 100644 --- a/ldap/servers/slapd/main.c +++ b/ldap/servers/slapd/main.c @@ -2118,7 +2118,7 @@ slapd_exemode_ldif2db() pb.pb_ldif_files = ldif_file; pb.pb_ldif_include = db2ldif_include; pb.pb_ldif_exclude = db2ldif_exclude; - pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE; + pb.pb_task_flags = SLAPI_TASK_RUNNING_FROM_COMMANDLINE; #ifndef _WIN32 main_setuid(slapdFrontendConfig->localuser); #endif @@ -2245,7 +2245,7 @@ slapd_exemode_db2ldif(int argc, char** argv) pb.pb_ldif_dump_uniqueid = db2ldif_dump_uniqueid; pb.pb_ldif_encrypt = importexport_encrypt; pb.pb_instance_name = *instp; - pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE; + pb.pb_task_flags = SLAPI_TASK_RUNNING_FROM_COMMANDLINE; if (is_slapd_running()) pb.pb_server_running = 1; else @@ -2431,7 +2431,7 @@ static int slapd_exemode_db2index() pb.pb_plugin = plugin; pb.pb_db2index_attrs = db2index_attrs; pb.pb_instance_name = cmd_line_instance_name; - pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE; + pb.pb_task_flags = SLAPI_TASK_RUNNING_FROM_COMMANDLINE; #ifndef _WIN32 main_setuid(slapdFrontendConfig->localuser); #endif @@ -2489,7 +2489,7 @@ slapd_exemode_db2archive() pb.pb_plugin = backend_plugin; pb.pb_instance_name = cmd_line_instance_name; pb.pb_seq_val = archive_name; - pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE; + pb.pb_task_flags = SLAPI_TASK_RUNNING_FROM_COMMANDLINE; #ifndef _WIN32 main_setuid(slapdFrontendConfig->localuser); #endif @@ -2539,7 +2539,7 @@ slapd_exemode_archive2db() pb.pb_plugin = backend_plugin; pb.pb_instance_name = cmd_line_instance_name; pb.pb_seq_val = archive_name; - pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE; + pb.pb_task_flags = SLAPI_TASK_RUNNING_FROM_COMMANDLINE; #ifndef _WIN32 main_setuid(slapdFrontendConfig->localuser); #endif @@ -2601,7 +2601,7 @@ slapd_exemode_upgradedb() pb.pb_plugin = backend_plugin; pb.pb_seq_val = archive_name; pb.pb_seq_type = upgradedb_force; - pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE; + pb.pb_task_flags = SLAPI_TASK_RUNNING_FROM_COMMANDLINE; /* borrowing import code, so need to set up the import variables */ pb.pb_ldif_generate_uniqueid = ldif2db_generate_uniqueid; pb.pb_ldif_namespaceid = ldif2db_namespaceid; @@ -2656,7 +2656,7 @@ slapd_exemode_dbverify() pb.pb_seq_type = dbverify_verbose; pb.pb_plugin = backend_plugin; pb.pb_instance_name = (char *)cmd_line_instance_names; - pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE; + pb.pb_task_flags = SLAPI_TASK_RUNNING_FROM_COMMANDLINE; if ( backend_plugin->plg_dbverify != NULL ) { return_value = (*backend_plugin->plg_dbverify)( &pb ); diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index f1777eb8..0b3305e3 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -1283,6 +1283,27 @@ typedef struct conn { #define SLAPD_POLL_FLAGS (PR_POLL_READ) #endif +/****************************************************************************** + * * Online tasks interface (to support import, export, etc) + * * After some cleanup, we could consider making these public. + * */ +struct slapi_task { + struct slapi_task *next; + char *task_dn; + int task_exitcode; /* for the end user */ + int task_state; /* current state of task */ + int task_progress; /* number between 0 and task_work */ + int task_work; /* "units" of work to be done */ + int task_flags; /* (see above) */ + char *task_status; /* transient status info */ + char *task_log; /* appended warnings, etc */ + void *task_private; /* allow opaque data to be stashed in the task */ + TaskCallbackFn cancel; /* task has been cancelled by user */ + TaskCallbackFn destructor; /* task entry is being destroyed */ + int task_refcount; +} slapi_task; +/* End of interface to support online tasks **********************************/ + typedef struct slapi_pblock { /* common */ Slapi_Backend *pb_backend; @@ -2016,10 +2037,6 @@ extern char *attr_dataversion; #include "intrinsics.h" -/* task flag (pb_task_flags)*/ -#define TASK_RUNNING_AS_TASK 0x0 -#define TASK_RUNNING_FROM_COMMANDLINE 0x1 - /* printkey: import & export */ #define EXPORT_PRINTKEY 0x1 #define EXPORT_NOWRAP 0x2 diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index f963621e..b7f5f927 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -149,9 +149,10 @@ typedef struct slapi_rdn Slapi_RDN; typedef struct slapi_mod Slapi_Mod; typedef struct slapi_mods Slapi_Mods; typedef struct slapi_componentid Slapi_ComponentId; + /* Online tasks interface (to support import, export, etc) */ -typedef struct _slapi_task Slapi_Task; -typedef int (*TaskCallbackFn)(Slapi_Task *task); +typedef struct slapi_task Slapi_Task; +typedef void (*TaskCallbackFn)(Slapi_Task *task); /* * The default thread stacksize for nspr21 is 64k (except on IRIX! It's 32k!). @@ -1206,6 +1207,22 @@ void slapi_register_role_check(roles_check_fn_type check_fn); typedef int (*dseCallbackFn)(Slapi_PBlock *, Slapi_Entry *, Slapi_Entry *, int *, char*, void *); +/* + * Note: DSE callback functions MUST return one of these three values: + * + * SLAPI_DSE_CALLBACK_OK -- no errors occurred; apply changes. + * SLAPI_DSE_CALLBACK_ERROR -- an error occurred; don't apply changes. + * SLAPI_DSE_CALLBACK_DO_NOT_APPLY -- no error, but do not apply changes. + * + * SLAPI_DSE_CALLBACK_DO_NOT_APPLY should only be returned by modify + * callbacks (i.e., those registered with operation==SLAPI_OPERATION_MODIFY). + * A return value of SLAPI_DSE_CALLBACK_DO_NOT_APPLY is treated the same as + * SLAPI_DSE_CALLBACK_ERROR for all other operations. + */ +#define SLAPI_DSE_CALLBACK_OK (1) +#define SLAPI_DSE_CALLBACK_ERROR (-1) +#define SLAPI_DSE_CALLBACK_DO_NOT_APPLY (0) + /****************************************************************************** * Online tasks interface (to support import, export, etc) * After some cleanup, we could consider making these public. @@ -1217,10 +1234,26 @@ typedef int (*dseCallbackFn)(Slapi_PBlock *, Slapi_Entry *, Slapi_Entry *, #define SLAPI_TASK_FINISHED 2 #define SLAPI_TASK_CANCELLED 3 +/* task flag (pb_task_flags)*/ +#define SLAPI_TASK_RUNNING_AS_TASK 0x0 +#define SLAPI_TASK_RUNNING_FROM_COMMANDLINE 0x1 + /* task flags (set by the task-control code) */ #define SLAPI_TASK_DESTROYING 0x01 /* queued event for destruction */ int slapi_task_register_handler(const char *name, dseCallbackFn func); +void slapi_task_begin(Slapi_Task *task, int total_work); +void slapi_task_inc_progress(Slapi_Task *task); +void slapi_task_finish(Slapi_Task *task, int rc); +void slapi_task_cancel(Slapi_Task *task, int rc); +int slapi_task_get_state(Slapi_Task *task); +void slapi_task_set_data(Slapi_Task *task, void *data); +void * slapi_task_get_data(Slapi_Task *task); +void slapi_task_inc_refcount(Slapi_Task *task); +void slapi_task_dec_refcount(Slapi_Task *task); +int slapi_task_get_refcount(Slapi_Task *task); +void slapi_task_set_destructor_fn(Slapi_Task *task, TaskCallbackFn func); +void slapi_task_set_cancel_fn(Slapi_Task *task, TaskCallbackFn func); void slapi_task_status_changed(Slapi_Task *task); void slapi_task_log_status(Slapi_Task *task, char *format, ...) #ifdef __GNUC__ diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h index 834ce46d..1225e8d5 100644 --- a/ldap/servers/slapd/slapi-private.h +++ b/ldap/servers/slapd/slapi-private.h @@ -1060,22 +1060,6 @@ int slapi_uniqueIDGenerateFromNameString(char **uId, */ /* - * Note: DSE callback functions MUST return one of these three values: - * - * SLAPI_DSE_CALLBACK_OK -- no errors occurred; apply changes. - * SLAPI_DSE_CALLBACK_ERROR -- an error occurred; don't apply changes. - * SLAPI_DSE_CALLBACK_DO_NOT_APPLY -- no error, but do not apply changes. - * - * SLAPI_DSE_CALLBACK_DO_NOT_APPLY should only be returned by modify - * callbacks (i.e., those registered with operation==SLAPI_OPERATION_MODIFY). - * A return value of SLAPI_DSE_CALLBACK_DO_NOT_APPLY is treated the same as - * SLAPI_DSE_CALLBACK_ERROR for all other operations. - */ -#define SLAPI_DSE_CALLBACK_OK (1) -#define SLAPI_DSE_CALLBACK_ERROR (-1) -#define SLAPI_DSE_CALLBACK_DO_NOT_APPLY (0) - -/* * Flags for slapi_config_register_callback() and * slapi_config_remove_callback() */ @@ -1198,30 +1182,6 @@ int slapd_re_init( void ); /***** End of items added for the replication plugin. ***********************/ -/****************************************************************************** - * Online tasks interface (to support import, export, etc) - * After some cleanup, we could consider making these public. - */ -struct _slapi_task { - struct _slapi_task *next; - char *task_dn; - int task_exitcode; /* for the end user */ - int task_state; /* (see above) */ - int task_progress; /* number between 0 and task_work */ - int task_work; /* "units" of work to be done */ - int task_flags; /* (see above) */ - - /* it is the task's responsibility to allocate this memory & free it: */ - char *task_status; /* transient status info */ - char *task_log; /* appended warnings, etc */ - - void *task_private; /* for use by backends */ - TaskCallbackFn cancel; /* task has been cancelled by user */ - TaskCallbackFn destructor; /* task entry is being destroyed */ - int task_refcount; -}; -/* End of interface to support online tasks **********************************/ - void DS_Sleep(PRIntervalTime ticks); /* macro to specify the behavior of upgradedb */ diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c index 13606c1c..67c93c16 100644 --- a/ldap/servers/slapd/task.c +++ b/ldap/servers/slapd/task.c @@ -47,6 +47,9 @@ #include "slap.h" +/*********************************** + * Static Global Variables + ***********************************/ /* don't panic, this is only used when creating new tasks or removing old * ones... */ @@ -54,7 +57,9 @@ static Slapi_Task *global_task_list = NULL; static PRLock *global_task_lock = NULL; static int shutting_down = 0; - +/*********************************** + * Private Defines + ***********************************/ #define TASK_BASE_DN "cn=tasks, cn=config" #define TASK_IMPORT_DN "cn=import, cn=tasks, cn=config" #define TASK_EXPORT_DN "cn=export, cn=tasks, cn=config" @@ -71,13 +76,398 @@ static int shutting_down = 0; #define DEFAULT_TTL "120" /* seconds */ +#define LOG_BUFFER 256 +/* if the cumul. log gets larger than this, it's truncated: */ +#define MAX_SCROLLBACK_BUFFER 8192 +#define NEXTMOD(_type, _val) do { \ + modlist[cur].mod_op = LDAP_MOD_REPLACE; \ + modlist[cur].mod_type = (_type); \ + modlist[cur].mod_values = (char **)slapi_ch_malloc(2*sizeof(char *)); \ + modlist[cur].mod_values[0] = (_val); \ + modlist[cur].mod_values[1] = NULL; \ + mod[cur] = &modlist[cur]; \ + cur++; \ +} while (0) + + +/*********************************** + * Static Function Prototypes + ***********************************/ +static Slapi_Task *new_task(const char *dn); +static void destroy_task(time_t when, void *arg); static int task_modify(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg); static int task_deny(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg); -static int task_generic_destructor(Slapi_Task *task); +static void task_generic_destructor(Slapi_Task *task); +static const char *fetch_attr(Slapi_Entry *e, const char *attrname, + const char *default_val); +static Slapi_Entry *get_internal_entry(Slapi_PBlock *pb, char *dn); +static void modify_internal_entry(char *dn, LDAPMod **mods); + +/*********************************** + * Public Functions + ***********************************/ +/* + * slapi_new_task: create a new task, fill in DN, and setup modify callback + * argument: + * dn: task dn + * result: + * Success: Slapi_Task object + * Failure: NULL + */ +Slapi_Task * +slapi_new_task(const char *dn) +{ + return new_task(dn); +} + +/* slapi_destroy_task: destroy a task + * argument: + * task: task to destroy + * result: + * none + */ +void +slapi_destroy_task(void *arg) +{ + if (arg) { + destroy_task(1, arg); + } +} + +/* + * Sets the initial task state and updated status + */ +void slapi_task_begin(Slapi_Task *task, int total_work) +{ + if (task) { + task->task_work = total_work; + task->task_progress = 0; + task->task_state = SLAPI_TASK_RUNNING; + slapi_task_status_changed(task); + } +} + +/* + * Increments task progress and updates status + */ +void slapi_task_inc_progress(Slapi_Task *task) +{ + if (task) { + task->task_progress++; + slapi_task_status_changed(task); + } +} + +/* + * Sets completed task state and updates status + */ +void slapi_task_finish(Slapi_Task *task, int rc) +{ + if (task) { + task->task_exitcode = rc; + task->task_state = SLAPI_TASK_FINISHED; + slapi_task_status_changed(task); + } +} + +/* + * Cancels a task + */ +void slapi_task_cancel(Slapi_Task *task, int rc) +{ + if (task) { + task->task_exitcode = rc; + task->task_state = SLAPI_TASK_CANCELLED; + slapi_task_status_changed(task); + } +} + +/* + * Get the current state of a task + */ +int slapi_task_get_state(Slapi_Task *task) +{ + if (task) { + return task->task_state; + } +} + +/* this changes the 'nsTaskStatus' value, which is transient (anything logged + * here wipes out any previous status) + */ +void slapi_task_log_status(Slapi_Task *task, char *format, ...) +{ + va_list ap; + + if (! task->task_status) + task->task_status = (char *)slapi_ch_malloc(10 * LOG_BUFFER); + if (! task->task_status) + return; /* out of memory? */ + + va_start(ap, format); + PR_vsnprintf(task->task_status, (10 * LOG_BUFFER), format, ap); + va_end(ap); + slapi_task_status_changed(task); +} + +/* this adds a line to the 'nsTaskLog' value, which is cumulative (anything + * logged here is added to the end) + */ +void slapi_task_log_notice(Slapi_Task *task, char *format, ...) +{ + va_list ap; + char buffer[LOG_BUFFER]; + size_t len; + + va_start(ap, format); + PR_vsnprintf(buffer, LOG_BUFFER, format, ap); + va_end(ap); + + len = 2 + strlen(buffer) + (task->task_log ? strlen(task->task_log) : 0); + if ((len > MAX_SCROLLBACK_BUFFER) && task->task_log) { + size_t i; + char *newbuf; + + /* start from middle of buffer, and find next linefeed */ + i = strlen(task->task_log)/2; + while (task->task_log[i] && (task->task_log[i] != '\n')) + i++; + if (task->task_log[i]) + i++; + len = strlen(task->task_log) - i + 2 + strlen(buffer); + newbuf = (char *)slapi_ch_malloc(len); + if (! newbuf) + return; /* out of memory? */ + strcpy(newbuf, task->task_log + i); + slapi_ch_free((void **)&task->task_log); + task->task_log = newbuf; + } else { + if (! task->task_log) { + task->task_log = (char *)slapi_ch_malloc(len); + task->task_log[0] = 0; + } else { + task->task_log = (char *)slapi_ch_realloc(task->task_log, len); + } + if (! task->task_log) + return; /* out of memory? */ + } + + if (task->task_log[0]) + strcat(task->task_log, "\n"); + strcat(task->task_log, buffer); + + slapi_task_status_changed(task); +} + +/* update attributes in the entry under "cn=tasks" to match the current + * status of the task. */ +void slapi_task_status_changed(Slapi_Task *task) +{ + LDAPMod modlist[20]; + LDAPMod *mod[20]; + int cur = 0, i; + char s1[20], s2[20], s3[20]; + + if (shutting_down) { + /* don't care about task status updates anymore */ + return; + } + + NEXTMOD(TASK_LOG_NAME, task->task_log); + NEXTMOD(TASK_STATUS_NAME, task->task_status); + sprintf(s1, "%d", task->task_exitcode); + sprintf(s2, "%d", task->task_progress); + sprintf(s3, "%d", task->task_work); + NEXTMOD(TASK_PROGRESS_NAME, s2); + NEXTMOD(TASK_WORK_NAME, s3); + /* only add the exit code when the job is done */ + if ((task->task_state == SLAPI_TASK_FINISHED) || + (task->task_state == SLAPI_TASK_CANCELLED)) { + NEXTMOD(TASK_EXITCODE_NAME, s1); + /* make sure the console can tell the task has ended */ + if (task->task_progress != task->task_work) { + task->task_progress = task->task_work; + } + } + + mod[cur] = NULL; + modify_internal_entry(task->task_dn, mod); + + for (i = 0; i < cur; i++) + slapi_ch_free((void **)&modlist[i].mod_values); + + if (((task->task_state == SLAPI_TASK_FINISHED) || + (task->task_state == SLAPI_TASK_CANCELLED)) && + !(task->task_flags & SLAPI_TASK_DESTROYING)) { + Slapi_PBlock *pb = slapi_pblock_new(); + Slapi_Entry *e; + int ttl; + time_t expire; + + e = get_internal_entry(pb, task->task_dn); + if (e == NULL) + return; + ttl = atoi(fetch_attr(e, "ttl", DEFAULT_TTL)); + if (ttl > 3600) + ttl = 3600; /* be reasonable. */ + expire = time(NULL) + ttl; + task->task_flags |= SLAPI_TASK_DESTROYING; + /* queue an event to destroy the state info */ + slapi_eq_once(destroy_task, (void *)task, expire); + + slapi_free_search_results_internal(pb); + slapi_pblock_destroy(pb); + } +} + +/* + * Stash some opaque task specific data in the task for later use. + */ +void slapi_task_set_data(Slapi_Task *task, void *data) +{ + if (task) { + task->task_private = data; + } +} + +/* + * Retrieve some opaque task specific data from the task. + */ +void * slapi_task_get_data(Slapi_Task *task) +{ + if (task) { + return task->task_private; + } +} + +/* + * Increment the task reference count + */ +void slapi_task_inc_refcount(Slapi_Task *task) +{ + if (task) { + task->task_refcount++; + } +} + +/* + * Decrement the task reference count + */ +void slapi_task_dec_refcount(Slapi_Task *task) +{ + if (task) { + task->task_refcount--; + } +} + +/* + * Returns the task reference count + */ +int slapi_task_get_refcount(Slapi_Task *task) +{ + if (task) { + return task->task_refcount; + } +} + +/* name is, for example, "import" */ +int slapi_task_register_handler(const char *name, dseCallbackFn func) +{ + char *dn = NULL; + Slapi_PBlock *pb = NULL; + Slapi_Operation *op; + LDAPMod *mods[3]; + LDAPMod mod[3]; + const char *objectclass[3]; + const char *cnvals[2]; + int ret = -1; + int x; + + dn = slapi_ch_smprintf("cn=%s, %s", name, TASK_BASE_DN); + if (dn == NULL) { + goto out; + } + + pb = slapi_pblock_new(); + if (pb == NULL) { + goto out; + } + + /* this is painful :( */ + mods[0] = &mod[0]; + mod[0].mod_op = LDAP_MOD_ADD; + mod[0].mod_type = "objectClass"; + mod[0].mod_values = (char **)objectclass; + objectclass[0] = "top"; + objectclass[1] = "extensibleObject"; + objectclass[2] = NULL; + mods[1] = &mod[1]; + mod[1].mod_op = LDAP_MOD_ADD; + mod[1].mod_type = "cn"; + mod[1].mod_values = (char **)cnvals; + cnvals[0] = name; + cnvals[1] = NULL; + mods[2] = NULL; + slapi_add_internal_set_pb(pb, dn, mods, NULL, + plugin_get_default_component_id(), 0); + x = 1; + slapi_pblock_set(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &x); + /* Make sure these adds don't appear in the audit and change logs */ + slapi_pblock_get(pb, SLAPI_OPERATION, &op); + operation_set_flag(op, OP_FLAG_ACTION_NOLOG); + + slapi_add_internal_pb(pb); + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &x); + if ((x != LDAP_SUCCESS) && (x != LDAP_ALREADY_EXISTS)) { + LDAPDebug(LDAP_DEBUG_ANY, + "Can't create task node '%s' (error %d)\n", + name, x, 0); + ret = x; + goto out; + } + + /* register add callback */ + slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, + dn, LDAP_SCOPE_SUBTREE, "(objectclass=*)", func, NULL); + /* deny modify/delete of the root task entry */ + slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, + dn, LDAP_SCOPE_BASE, "(objectclass=*)", task_deny, NULL); + slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, + dn, LDAP_SCOPE_BASE, "(objectclass=*)", task_deny, NULL); + + ret = 0; + +out: + if (dn) { + slapi_ch_free((void **)&dn); + } + if (pb) { + slapi_pblock_destroy(pb); + } + return ret; +} + +void slapi_task_set_destructor_fn(Slapi_Task *task, TaskCallbackFn func) +{ + if (task) { + task->destructor = func; + } +} + +void slapi_task_set_cancel_fn(Slapi_Task *task, TaskCallbackFn func) +{ + if (task) { + task->cancel = func; + } +} + +/*********************************** + * Static Helper Functions + ***********************************/ /* create a new task, fill in DN, and setup modify callback */ static Slapi_Task * new_task(const char *dn) @@ -92,7 +482,11 @@ new_task(const char *dn) PR_Unlock(global_task_lock); task->task_dn = slapi_ch_strdup(dn); - task->destructor = task_generic_destructor; + task->task_state = SLAPI_TASK_SETUP; + task->task_flags = SLAPI_TASK_RUNNING_AS_TASK; + task->destructor = NULL; + task->cancel = NULL; + task->task_private = NULL; slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn, LDAP_SCOPE_BASE, "(objectclass=*)", task_modify, (void *)task); slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, dn, @@ -100,8 +494,8 @@ new_task(const char *dn) /* don't add entries under this one */ #if 0 /* don't know why, but this doesn't work. it makes the current add - * operation fail. :( - */ + * * operation fail. :( + * */ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn, LDAP_SCOPE_SUBTREE, "(objectclass=*)", task_deny, NULL); #endif @@ -117,8 +511,13 @@ destroy_task(time_t when, void *arg) Slapi_Task *t1; Slapi_PBlock *pb = slapi_pblock_new(); - if (task->destructor != NULL) + /* Call the custom destructor callback if one was provided, + * then perform the internal task destruction. */ + if (task->destructor != NULL) { (*task->destructor)(task); + } + + task_generic_destructor(task); /* if when == 0, we're already locked (called during shutdown) */ if (when != 0) { @@ -152,35 +551,6 @@ destroy_task(time_t when, void *arg) slapi_ch_free((void **)&task); } -/* - * slapi_new_task: create a new task, fill in DN, and setup modify callback - * argument: - * dn: task dn - * result: - * Success: Slapi_Task object - * Failure: NULL - */ -Slapi_Task * -slapi_new_task(const char *dn) -{ - return new_task(dn); -} - -/* slapi_destroy_task: destroy a task - * argument: - * task: task to destroy - * result: - * none - */ -void -slapi_destroy_task(void *arg) -{ - destroy_task(1, arg); -} - -/********** some useful helper functions **********/ - - /* extract a single value from the entry (as a string) -- if it's not in the * entry, the default will be returned (which can be NULL). * you do not need to free anything returned by this. @@ -268,81 +638,7 @@ static void modify_internal_entry(char *dn, LDAPMod **mods) } while (ret != LDAP_SUCCESS); } - -/********** helper functions for dealing with task logging **********/ - -#define LOG_BUFFER 256 -/* if the cumul. log gets larger than this, it's truncated: */ -#define MAX_SCROLLBACK_BUFFER 8192 - -/* this changes the 'nsTaskStatus' value, which is transient (anything logged - * here wipes out any previous status) - */ -void slapi_task_log_status(Slapi_Task *task, char *format, ...) -{ - va_list ap; - - if (! task->task_status) - task->task_status = (char *)slapi_ch_malloc(10 * LOG_BUFFER); - if (! task->task_status) - return; /* out of memory? */ - - va_start(ap, format); - PR_vsnprintf(task->task_status, (10 * LOG_BUFFER), format, ap); - va_end(ap); - slapi_task_status_changed(task); -} - -/* this adds a line to the 'nsTaskLog' value, which is cumulative (anything - * logged here is added to the end) - */ -void slapi_task_log_notice(Slapi_Task *task, char *format, ...) -{ - va_list ap; - char buffer[LOG_BUFFER]; - size_t len; - - va_start(ap, format); - PR_vsnprintf(buffer, LOG_BUFFER, format, ap); - va_end(ap); - - len = 2 + strlen(buffer) + (task->task_log ? strlen(task->task_log) : 0); - if ((len > MAX_SCROLLBACK_BUFFER) && task->task_log) { - size_t i; - char *newbuf; - - /* start from middle of buffer, and find next linefeed */ - i = strlen(task->task_log)/2; - while (task->task_log[i] && (task->task_log[i] != '\n')) - i++; - if (task->task_log[i]) - i++; - len = strlen(task->task_log) - i + 2 + strlen(buffer); - newbuf = (char *)slapi_ch_malloc(len); - if (! newbuf) - return; /* out of memory? */ - strcpy(newbuf, task->task_log + i); - slapi_ch_free((void **)&task->task_log); - task->task_log = newbuf; - } else { - if (! task->task_log) { - task->task_log = (char *)slapi_ch_malloc(len); - task->task_log[0] = 0; - } else { - task->task_log = (char *)slapi_ch_realloc(task->task_log, len); - } - if (! task->task_log) - return; /* out of memory? */ - } - - if (task->task_log[0]) - strcat(task->task_log, "\n"); - strcat(task->task_log, buffer); - - slapi_task_status_changed(task); -} - -static int task_generic_destructor(Slapi_Task *task) +static void task_generic_destructor(Slapi_Task *task) { if (task->task_log) { slapi_ch_free((void **)&task->task_log); @@ -351,7 +647,6 @@ static int task_generic_destructor(Slapi_Task *task) slapi_ch_free((void **)&task->task_status); } task->task_log = task->task_status = NULL; - return 0; } @@ -553,13 +848,12 @@ static int task_import_add(Slapi_PBlock *pb, Slapi_Entry *e, } /* allocate new task now */ - task = new_task(slapi_entry_get_ndn(e)); + task = slapi_new_task(slapi_entry_get_ndn(e)); if (task == NULL) { LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0); rv = LDAP_OPERATIONS_ERROR; goto out; } - task->task_state = SLAPI_TASK_SETUP; memset(&mypb, 0, sizeof(mypb)); mypb.pb_backend = be; @@ -575,7 +869,7 @@ static int task_import_add(Slapi_PBlock *pb, Slapi_Entry *e, mypb.pb_ldif_include = include; mypb.pb_ldif_exclude = exclude; mypb.pb_task = task; - mypb.pb_task_flags = TASK_RUNNING_AS_TASK; + mypb.pb_task_flags = SLAPI_TASK_RUNNING_AS_TASK; if (NULL != encrypt_on_import && 0 == strcasecmp(encrypt_on_import, "true") ) { mypb.pb_ldif_encrypt = 1; } @@ -618,10 +912,7 @@ static void task_export_thread(void *arg) g_incr_active_threadcnt(); for (count = 0, inp = instance_names; *inp; inp++, count++) ; - task->task_work = count; - task->task_progress = 0; - task->task_state = SLAPI_TASK_RUNNING; - slapi_task_status_changed(task); + slapi_task_begin(task, count); for (inp = instance_names; *inp; inp++) { int release_me = 0; @@ -693,8 +984,7 @@ static void task_export_thread(void *arg) if (rv != 0) break; - task->task_progress++; - slapi_task_status_changed(task); + slapi_task_inc_progress(task); } /* free the memory now */ @@ -712,9 +1002,7 @@ static void task_export_thread(void *arg) LDAPDebug(LDAP_DEBUG_ANY, "Export failed.\n", 0, 0, 0); } - task->task_exitcode = rv; - task->task_state = SLAPI_TASK_FINISHED; - slapi_task_status_changed(task); + slapi_task_finish(task, rv); g_decr_active_threadcnt(); } @@ -888,16 +1176,13 @@ static int task_export_add(Slapi_PBlock *pb, Slapi_Entry *e, } /* allocate new task now */ - task = new_task(slapi_entry_get_ndn(e)); + task = slapi_new_task(slapi_entry_get_ndn(e)); if (task == NULL) { LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0); *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } - task->task_state = SLAPI_TASK_SETUP; - task->task_work = instance_cnt; - task->task_progress = 0; mypb = slapi_pblock_new(); if (mypb == NULL) { @@ -914,7 +1199,7 @@ static int task_export_add(Slapi_PBlock *pb, Slapi_Entry *e, /* horrible hack */ mypb->pb_instance_name = (char *)instance_names; mypb->pb_task = task; - mypb->pb_task_flags = TASK_RUNNING_AS_TASK; + mypb->pb_task_flags = SLAPI_TASK_RUNNING_AS_TASK; if (NULL != decrypt_on_export && 0 == strcasecmp(decrypt_on_export, "true") ) { mypb->pb_ldif_encrypt = 1; } @@ -957,10 +1242,7 @@ static void task_backup_thread(void *arg) int rv; g_incr_active_threadcnt(); - task->task_work = 1; - task->task_progress = 0; - task->task_state = SLAPI_TASK_RUNNING; - slapi_task_status_changed(task); + slapi_task_begin(task, 1); slapi_task_log_notice(task, "Beginning backup of '%s'", pb->pb_plugin->plg_name); @@ -978,11 +1260,7 @@ static void task_backup_thread(void *arg) LDAPDebug(LDAP_DEBUG_ANY, "Backup finished.\n", 0, 0, 0); } - task->task_progress = 1; - task->task_exitcode = rv; - task->task_state = SLAPI_TASK_FINISHED; - slapi_task_status_changed(task); - + slapi_task_finish(task, rv); slapi_ch_free((void **)&pb->pb_seq_val); slapi_pblock_destroy(pb); g_decr_active_threadcnt(); @@ -1048,16 +1326,13 @@ static int task_backup_add(Slapi_PBlock *pb, Slapi_Entry *e, } /* allocate new task now */ - task = new_task(slapi_entry_get_ndn(e)); + task = slapi_new_task(slapi_entry_get_ndn(e)); if (task == NULL) { LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0); *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } - task->task_state = SLAPI_TASK_SETUP; - task->task_work = 1; - task->task_progress = 0; mypb = slapi_pblock_new(); if (mypb == NULL) { @@ -1068,7 +1343,7 @@ static int task_backup_add(Slapi_PBlock *pb, Slapi_Entry *e, mypb->pb_seq_val = slapi_ch_strdup(archive_dir); mypb->pb_plugin = be->be_database; mypb->pb_task = task; - mypb->pb_task_flags = TASK_RUNNING_AS_TASK; + mypb->pb_task_flags = SLAPI_TASK_RUNNING_AS_TASK; /* start the backup as a separate thread */ thread = PR_CreateThread(PR_USER_THREAD, task_backup_thread, @@ -1102,10 +1377,7 @@ static void task_restore_thread(void *arg) int rv; g_incr_active_threadcnt(); - task->task_work = 1; - task->task_progress = 0; - task->task_state = SLAPI_TASK_RUNNING; - slapi_task_status_changed(task); + slapi_task_begin(task, 1); slapi_task_log_notice(task, "Beginning restore to '%s'", pb->pb_plugin->plg_name); @@ -1123,11 +1395,7 @@ static void task_restore_thread(void *arg) LDAPDebug(LDAP_DEBUG_ANY, "Restore finished.\n", 0, 0, 0); } - task->task_progress = 1; - task->task_exitcode = rv; - task->task_state = SLAPI_TASK_FINISHED; - slapi_task_status_changed(task); - + slapi_task_finish(task, rv); slapi_ch_free((void **)&pb->pb_seq_val); slapi_pblock_destroy(pb); g_decr_active_threadcnt(); @@ -1199,16 +1467,13 @@ static int task_restore_add(Slapi_PBlock *pb, Slapi_Entry *e, } /* allocate new task now */ - task = new_task(slapi_entry_get_ndn(e)); + task = slapi_new_task(slapi_entry_get_ndn(e)); if (task == NULL) { LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0); *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } - task->task_state = SLAPI_TASK_SETUP; - task->task_work = 1; - task->task_progress = 0; mypb = slapi_pblock_new(); if (mypb == NULL) { @@ -1221,7 +1486,7 @@ static int task_restore_add(Slapi_PBlock *pb, Slapi_Entry *e, if (NULL != instance_name) mypb->pb_instance_name = slapi_ch_strdup(instance_name); mypb->pb_task = task; - mypb->pb_task_flags = TASK_RUNNING_AS_TASK; + mypb->pb_task_flags = SLAPI_TASK_RUNNING_AS_TASK; /* start the restore as a separate thread */ thread = PR_CreateThread(PR_USER_THREAD, task_restore_thread, @@ -1255,10 +1520,7 @@ static void task_index_thread(void *arg) int rv; g_incr_active_threadcnt(); - task->task_work = 1; - task->task_progress = 0; - task->task_state = SLAPI_TASK_RUNNING; - slapi_task_status_changed(task); + slapi_task_begin(task, 1); rv = (*pb->pb_plugin->plg_db2index)(pb); if (rv != 0) { @@ -1267,11 +1529,7 @@ static void task_index_thread(void *arg) LDAPDebug(LDAP_DEBUG_ANY, "Index failed (error %d)\n", rv, 0, 0); } - task->task_progress = task->task_work; - task->task_exitcode = rv; - task->task_state = SLAPI_TASK_FINISHED; - slapi_task_status_changed(task); - + slapi_task_finish(task, rv); charray_free(pb->pb_db2index_attrs); slapi_ch_free((void **)&pb->pb_instance_name); slapi_pblock_destroy(pb); @@ -1353,16 +1611,13 @@ static int task_index_add(Slapi_PBlock *pb, Slapi_Entry *e, } /* allocate new task now */ - task = new_task(slapi_entry_get_ndn(e)); + task = slapi_new_task(slapi_entry_get_ndn(e)); if (task == NULL) { LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0); *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } - task->task_state = SLAPI_TASK_SETUP; - task->task_work = 1; - task->task_progress = 0; mypb = slapi_pblock_new(); if (mypb == NULL) { @@ -1375,7 +1630,7 @@ static int task_index_add(Slapi_PBlock *pb, Slapi_Entry *e, mypb->pb_instance_name = slapi_ch_strdup(instance_name); mypb->pb_db2index_attrs = indexlist; mypb->pb_task = task; - mypb->pb_task_flags = TASK_RUNNING_AS_TASK; + mypb->pb_task_flags = SLAPI_TASK_RUNNING_AS_TASK; /* start the db2index as a separate thread */ thread = PR_CreateThread(PR_USER_THREAD, task_index_thread, @@ -1460,14 +1715,14 @@ task_upgradedb_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, } /* allocate new task now */ - task = new_task(slapi_entry_get_ndn(e)); + task = slapi_new_task(slapi_entry_get_ndn(e)); if (task == NULL) { LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0); *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } - task->task_state = SLAPI_TASK_SETUP; + /* NGK - This could use some cleanup to use the SLAPI task API, such as slapi_task_begin() */ task->task_work = 1; task->task_progress = 0; @@ -1478,7 +1733,7 @@ task_upgradedb_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, mypb.pb_seq_type = SLAPI_UPGRADEDB_FORCE; /* force; reindex all regardless the dbversion */ mypb.pb_seq_val = slapi_ch_strdup(archive_dir); mypb.pb_task = task; - mypb.pb_task_flags = TASK_RUNNING_AS_TASK; + mypb.pb_task_flags = SLAPI_TASK_RUNNING_AS_TASK; rv = (mypb.pb_plugin->plg_upgradedb)(&mypb); if (rv == 0) { @@ -1502,76 +1757,6 @@ out: return SLAPI_DSE_CALLBACK_OK; } -/* update attributes in the entry under "cn=tasks" to match the current - * status of the task. - */ -#define NEXTMOD(_type, _val) do { \ - modlist[cur].mod_op = LDAP_MOD_REPLACE; \ - modlist[cur].mod_type = (_type); \ - modlist[cur].mod_values = (char **)slapi_ch_malloc(2*sizeof(char *)); \ - modlist[cur].mod_values[0] = (_val); \ - modlist[cur].mod_values[1] = NULL; \ - mod[cur] = &modlist[cur]; \ - cur++; \ -} while (0) -void slapi_task_status_changed(Slapi_Task *task) -{ - LDAPMod modlist[20]; - LDAPMod *mod[20]; - int cur = 0, i; - char s1[20], s2[20], s3[20]; - - if (shutting_down) { - /* don't care about task status updates anymore */ - return; - } - - NEXTMOD(TASK_LOG_NAME, task->task_log); - NEXTMOD(TASK_STATUS_NAME, task->task_status); - sprintf(s1, "%d", task->task_exitcode); - sprintf(s2, "%d", task->task_progress); - sprintf(s3, "%d", task->task_work); - NEXTMOD(TASK_PROGRESS_NAME, s2); - NEXTMOD(TASK_WORK_NAME, s3); - /* only add the exit code when the job is done */ - if ((task->task_state == SLAPI_TASK_FINISHED) || - (task->task_state == SLAPI_TASK_CANCELLED)) { - NEXTMOD(TASK_EXITCODE_NAME, s1); - /* make sure the console can tell the task has ended */ - if (task->task_progress != task->task_work) { - task->task_progress = task->task_work; - } - } - - mod[cur] = NULL; - modify_internal_entry(task->task_dn, mod); - - for (i = 0; i < cur; i++) - slapi_ch_free((void **)&modlist[i].mod_values); - - if ((task->task_state == SLAPI_TASK_FINISHED) && - !(task->task_flags & SLAPI_TASK_DESTROYING)) { - Slapi_PBlock *pb = slapi_pblock_new(); - Slapi_Entry *e; - int ttl; - time_t expire; - - e = get_internal_entry(pb, task->task_dn); - if (e == NULL) - return; - ttl = atoi(fetch_attr(e, "ttl", DEFAULT_TTL)); - if (ttl > 3600) - ttl = 3600; /* be reasonable. */ - expire = time(NULL) + ttl; - task->task_flags |= SLAPI_TASK_DESTROYING; - /* queue an event to destroy the state info */ - slapi_eq_once(destroy_task, (void *)task, expire); - - slapi_free_search_results_internal(pb); - slapi_pblock_destroy(pb); - } -} - /* cleanup old tasks that may still be in the DSE from a previous session * (this can happen if the server crashes [no matter how unlikely we like * to think that is].) @@ -1636,84 +1821,6 @@ void task_cleanup(void) slapi_pblock_destroy(pb); } -/* name is, for exmaple, "import" */ -int slapi_task_register_handler(const char *name, dseCallbackFn func) -{ - char *dn = NULL; - Slapi_PBlock *pb = NULL; - Slapi_Operation *op; - LDAPMod *mods[3]; - LDAPMod mod[3]; - const char *objectclass[3]; - const char *cnvals[2]; - int ret = -1; - int x; - - dn = slapi_ch_smprintf("cn=%s, %s", name, TASK_BASE_DN); - if (dn == NULL) { - goto out; - } - - pb = slapi_pblock_new(); - if (pb == NULL) { - goto out; - } - - /* this is painful :( */ - mods[0] = &mod[0]; - mod[0].mod_op = LDAP_MOD_ADD; - mod[0].mod_type = "objectClass"; - mod[0].mod_values = (char **)objectclass; - objectclass[0] = "top"; - objectclass[1] = "extensibleObject"; - objectclass[2] = NULL; - mods[1] = &mod[1]; - mod[1].mod_op = LDAP_MOD_ADD; - mod[1].mod_type = "cn"; - mod[1].mod_values = (char **)cnvals; - cnvals[0] = name; - cnvals[1] = NULL; - mods[2] = NULL; - slapi_add_internal_set_pb(pb, dn, mods, NULL, - plugin_get_default_component_id(), 0); - x = 1; - slapi_pblock_set(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &x); - /* Make sure these adds don't appear in the audit and change logs */ - slapi_pblock_get(pb, SLAPI_OPERATION, &op); - operation_set_flag(op, OP_FLAG_ACTION_NOLOG); - - slapi_add_internal_pb(pb); - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &x); - if ((x != LDAP_SUCCESS) && (x != LDAP_ALREADY_EXISTS)) { - LDAPDebug(LDAP_DEBUG_ANY, - "Can't create task node '%s' (error %d)\n", - name, x, 0); - ret = x; - goto out; - } - - /* register add callback */ - slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, - dn, LDAP_SCOPE_SUBTREE, "(objectclass=*)", func, NULL); - /* deny modify/delete of the root task entry */ - slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, - dn, LDAP_SCOPE_BASE, "(objectclass=*)", task_deny, NULL); - slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, - dn, LDAP_SCOPE_BASE, "(objectclass=*)", task_deny, NULL); - - ret = 0; - -out: - if (dn) { - slapi_ch_free((void **)&dn); - } - if (pb) { - slapi_pblock_destroy(pb); - } - return ret; -} - - void task_init(void) { global_task_lock = PR_NewLock(); diff --git a/ldap/servers/slapd/test-plugins/sampletask.c b/ldap/servers/slapd/test-plugins/sampletask.c index 94f1ade8..357ed5ca 100644 --- a/ldap/servers/slapd/test-plugins/sampletask.c +++ b/ldap/servers/slapd/test-plugins/sampletask.c @@ -47,7 +47,7 @@ * objectClass: nsSlapdPlugin * objectClass: extensibleObject * cn: sampletask - * nsslapd-pluginPath: <prefix>/usr/lib/<PACKAGE_NAME>/plugins/libsampletask-plugin.so + * nsslapd-pluginPath: libsampletask-plugin * nsslapd-pluginInitfunc: sampletask_init * nsslapd-pluginType: object * nsslapd-pluginEnabled: on @@ -58,26 +58,26 @@ * * 4. create a config task entry in dse.ldif * Task entry: - * dn: cn=sample task, cn=tasks, cn=config + * dn: cn=sampletask, cn=tasks, cn=config * objectClass: top * objectClass: extensibleObject - * cn: sample task + * cn: sampletask * * 5. to invoke the sample task, run the command line: * $ ./ldapmodify -h <host> -p <port> -D "cn=Directory Manager" -w <pw> -a - * dn: cn=sample task 0, cn=sample task, cn=tasks, cn=config + * dn: cn=sampletask 0, cn=sample task, cn=tasks, cn=config * objectClass: top * objectClass: extensibleObject * cn: sample task 0 - * arg0: sample task arg0 + * myarg: sample task myarg * * Result is in the errors log - * [...] - Sample task starts (arg: sample task arg0) ... + * [...] - Sample task starts (arg: sample task myarg) ... * [...] - Sample task finished. */ -#include "slap.h" -#include "slapi-private.h" +#include "slapi-plugin.h" +#include "nspr.h" static int task_sampletask_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, @@ -118,33 +118,32 @@ task_sampletask_start(Slapi_PBlock *pb) static void task_sampletask_thread(void *arg) { - Slapi_PBlock *pb = (Slapi_PBlock *)arg; - Slapi_Task *task = pb->pb_task; - int rv; - - task->task_work = 1; - task->task_progress = 0; - task->task_state = SLAPI_TASK_RUNNING; - slapi_task_status_changed(task); - - slapi_task_log_notice(task, "Sample task starts (arg: %s) ...\n", - pb->pb_seq_val); - LDAPDebug(LDAP_DEBUG_ANY, "Sample task starts (arg: %s) ...\n", - pb->pb_seq_val, 0, 0); - /* do real work */ - rv = 0; + Slapi_Task *task = (Slapi_Task *)arg; + char *myarg = NULL; + int i, rv = 0; + int total_work = 3; + + /* fetch our argument from the task */ + myarg = (char *)slapi_task_get_data(task); + + /* update task state to show it's running */ + slapi_task_begin(task, total_work); + slapi_task_log_notice(task, "Sample task starts (arg: %s) ...\n", myarg); + slapi_log_error(SLAPI_LOG_FATAL, "sampletask", "Sample task starts (arg: %s) ...\n", myarg); + + /* real work would be done here */ + for (i = 0; i < total_work; i++) { + PR_Sleep(10000); + slapi_task_inc_progress(task); + } + /* update task state to say we're finished */ slapi_task_log_notice(task, "Sample task finished."); slapi_task_log_status(task, "Sample task finished."); - LDAPDebug(LDAP_DEBUG_ANY, "Sample task finished.\n", 0, 0, 0); - - task->task_progress = 1; - task->task_exitcode = rv; - task->task_state = SLAPI_TASK_FINISHED; - slapi_task_status_changed(task); + slapi_log_error(SLAPI_LOG_FATAL, "sampletask", "Sample task finished.\n"); - slapi_ch_free((void **)&pb->pb_seq_val); - slapi_pblock_destroy(pb); + /* this will queue the destruction of the task */ + slapi_task_finish(task, rv); } /* extract a single value from the entry (as a string) -- if it's not in the @@ -163,6 +162,17 @@ static const char *fetch_attr(Slapi_Entry *e, const char *attrname, return slapi_value_get_string(val); } +static void +task_sampletask_destructor(Slapi_Task *task) +{ + if (task) { + char *myarg = (char *)slapi_task_get_data(task); + if (myarg) { + slapi_ch_free_string(&myarg); + } + } +} + /* * Invoked when the task instance is added by the client (step 5 of the comment) * Get the necessary attributes from the task entry, and spawns a thread to do @@ -178,7 +188,7 @@ task_sampletask_add(Slapi_PBlock *pb, Slapi_Entry *e, int rv = SLAPI_DSE_CALLBACK_OK; Slapi_PBlock *mypb = NULL; Slapi_Task *task = NULL; - const char *arg0; + const char *myarg; *returncode = LDAP_SUCCESS; if ((cn = fetch_attr(e, "cn", NULL)) == NULL) { @@ -188,7 +198,7 @@ task_sampletask_add(Slapi_PBlock *pb, Slapi_Entry *e, } /* get arg(s) */ - if ((arg0 = fetch_attr(e, "arg0", NULL)) == NULL) { + if ((myarg = fetch_attr(e, "myarg", NULL)) == NULL) { *returncode = LDAP_OBJECT_CLASS_VIOLATION; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; @@ -197,46 +207,33 @@ task_sampletask_add(Slapi_PBlock *pb, Slapi_Entry *e, /* allocate new task now */ task = slapi_new_task(slapi_entry_get_ndn(e)); if (task == NULL) { - LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0); + slapi_log_error(SLAPI_LOG_FATAL, "sampletask", "unable to allocate new task!\n"); *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } - task->task_state = SLAPI_TASK_SETUP; - task->task_work = 1; - task->task_progress = 0; - /* create a pblock to pass the necessary info to the task thread */ - mypb = slapi_pblock_new(); - if (mypb == NULL) { - *returncode = LDAP_OPERATIONS_ERROR; - rv = SLAPI_DSE_CALLBACK_ERROR; - goto out; - } - mypb->pb_seq_val = slapi_ch_strdup(arg0); - mypb->pb_task = task; - mypb->pb_task_flags = TASK_RUNNING_AS_TASK; + /* set a destructor that will clean up myarg for us when the task is complete */ + slapi_task_set_destructor_fn(task, task_sampletask_destructor); + + /* Stash our argument in the task for use by the task thread */ + slapi_task_set_data(task, slapi_ch_strdup(myarg)); /* start the sample task as a separate thread */ thread = PR_CreateThread(PR_USER_THREAD, task_sampletask_thread, - (void *)mypb, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE); if (thread == NULL) { - LDAPDebug(LDAP_DEBUG_ANY, - "unable to create sample task thread!\n", 0, 0, 0); + slapi_log_error(SLAPI_LOG_FATAL, "sampletask", + "unable to create sample task thread!\n"); *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; - slapi_ch_free((void **)&mypb->pb_seq_val); - slapi_pblock_destroy(mypb); - goto out; + slapi_task_finish(task, *returncode); + } else { + /* thread successful */ + rv = SLAPI_DSE_CALLBACK_OK; } - /* thread successful -- don't free the pb, let the thread do that. */ - return SLAPI_DSE_CALLBACK_OK; - out: - if (task) { - slapi_destroy_task(task); - } return rv; } |