mm_task.c revision d1d2228c6cf3ec632d28262810ab7902932a5d33
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <mms_list.h>
#include <mms_parser.h>
#include <libpq-fe.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <syslog.h>
#include <mms_trace.h>
#include <mms_strapp.h>
#include "mm_db.h"
#include "mm.h"
#include "mm_util.h"
#include "mm_sql.h"
#include "mm_commands.h"
#include "mm_sql.h"
#include "mm_sql_impl.h"
#include "mm_task.h"
#define MM_BE_ERROR 0
#define MM_BE_DISPATCH 1
#define MM_BE_BLOCKING 2
#define MM_BE_OK 3
/* if drive is NULL return the 1st drive in the list */
"1st drive was NULL");
}
return (cur_drive);
}
drive) == 0) {
return (cur_drive);
}
}
return (NULL);
}
cart_id) == 0) {
return (cur_cart);
}
}
return (NULL);
}
char *
/* Return the dm name for drive_name on host */
"select \"DMName\" from \"DM\" "
"where \"DM\".\"DriveName\" = '%s' and "
" pg_host_ident(\"DMTargetHost\") "
"= pg_host_ident('%s');",
"db error, tm_return_dm_name");
return (NULL);
}
"row num mismatch , tm_return_dm_name");
return (NULL);
}
return (dm_name);
}
int
{
/* Use this function for both unmout and mounts */
int rc;
"tm_can_dispatch_mount");
switch (rc) {
case MM_MOUNT_ERROR:
/* Error code should be set */
"internal error, mm_mount_ready");
return (0);
case MM_MOUNT_READY:
/* The mount is ready, mount_info should be set */
/* continue to state 1 */
"mount is ready to go, "
"continue to state 1");
return (1);
case MM_MOUNT_NEED_UNLOAD:
/* this immediate mount needs to */
/* wait for an unload */
"mount waiting "
"for unload to complete");
return (1);
case MM_MOUNT_NOT_READY:
/* Error code should be set */
"blocking mount not ready, "
"wait longer and try later");
return (0);
default:
"bad rc mm_mount_ready");
"bad rc mm_mount_ready");
return (0);
}
}
/* returns ordered list of inuse candidate cartridges */
/* for task_id */
"from \"CARTRIDGE\" "
"where \"CartridgeStatus\" = 'in use' "
"and \"CartridgeID\" "
"in (select distinct \"CartridgeID\" "
"from \"TASKCARTRIDGE\" "
"where \"TaskID\" = '%s') "
"order by \"CartridgeNumberMounts\";",
task_id) != MM_DB_DATA) {
"db_error, tm_get_inuse_carts");
return (NULL);
}
return (db->mm_db_results);
}
int
{
int rc;
"tm_can_dispatch_unmount");
switch (rc) {
case MM_UNMOUNT_ERROR:
/* Error code should be set */
"internal error, mm_unmount_ready");
return (0);
case MM_UNMOUNT_READY:
/* The unmount is ready, unmount_info should be set */
/* continue to state 1 */
"unmount is ready to go, "
"continue to state 1");
return (1);
case MM_UNMOUNT_NOT_READY:
/* Error code should be set */
"blocking unmount not ready, "
"wait longer and try later");
return (0);
default:
"bad rc mm_unmount_ready");
"bad rc mm_unmount_ready");
return (0);
}
}
int
if (cart->cmi_cart_not_ready) {
}
if (drive->cmi_drive_not_ready) {
}
}
}
return (0);
}
int
mm_command_t *end_cmd) {
int cart_rows;
int found_cart_drive = 0;
int found_ready_cart_drive = 0;
"error getting candidate "
"cartridge");
/* No carts or error */
return (MM_UNMOUNT_ERROR);
}
if (cart_rows == 0) {
/* No Cartridge Matches Error */
"match statment in mount "
NULL);
return (MM_UNMOUNT_ERROR);
}
/* Create the list objects for */
db)) {
"error initializing candidate lists");
/* err buf should be set by mm_mount_init */
/* so return and remove */
"error init candidate lists");
return (MM_UNMOUNT_ERROR);
}
/* Check the availability of the candidates */
db)) {
"error checking candidate lists");
"error checking candidate lists");
return (MM_UNMOUNT_ERROR);
}
/* Print mount information */
found_cart_drive = 0;
found_cart_drive = 1;
if ((cart->cmi_cart_not_ready == 0) &&
(drive->cmi_drive_not_ready == 0)) {
}
}
}
/* If there is a library or drive error */
/* the error buff has already been set */
if (found_cart_drive == 0) {
"No candidate "
"combination found");
"ENOSOLUTIONS",
NULL);
return (MM_UNMOUNT_ERROR);
}
if (found_ready_cart_drive == 0) {
"candidate "
"combination found, but is not ready");
"ETMPUNAVAIL",
NULL);
return (MM_UNMOUNT_NOT_READY);
}
return (MM_UNMOUNT_READY);
}
int
mm_command_t *end_cmd) {
int cart_rows;
int found_cart_drive = 0;
int found_ready_cart_drive = 0;
/* Need to set end_cmd buf correctly for any MM_MOUNT_ERROR return */
"error getting candidate "
"cartridge");
/* No carts or error */
return (MM_MOUNT_ERROR);
}
if (cart_rows == 0) {
/* No Cartridge Matches Error */
"match statment in mount "
NULL);
return (MM_MOUNT_ERROR);
}
/* Create the list objects for */
db)) {
"error initializing candidate lists");
/* err buf should be set by mm_mount_init */
/* so return and remove */
"error init candidate lists");
return (MM_MOUNT_ERROR);
}
/* Check the availability of the candidates */
db)) {
"error checking candidate lists");
"error checking candidate lists");
return (MM_MOUNT_ERROR);
}
/* Print mount information */
/*
* For blocking mounts,
*
* for immediate mounts, check that at least one combination exists
*/
found_cart_drive = 0;
found_cart_drive = 1;
if ((cart->cmi_cart_not_ready == 0) &&
(drive->cmi_drive_not_ready == 0)) {
}
}
}
/* If there is a library or drive error */
/* the error buff has already been set */
if (found_cart_drive == 0) {
"No candidate "
"combination found");
/* If this cmd has a retry error class */
/* Send a retry error */
/* This is a retry error */
"Error is from a retry error");
"ETMPUNAVAIL",
NULL);
return (MM_MOUNT_ERROR);
}
"ENOSOLUTIONS",
NULL);
return (MM_MOUNT_ERROR);
}
if (found_ready_cart_drive == 0) {
"candidate "
"combination found, but is not ready");
"ETMPUNAVAIL",
NULL);
return (MM_MOUNT_NOT_READY);
}
return (MM_MOUNT_READY);
}
#define TM_CANCEL_RESPONSE "response task[\"%s\"] cancelled;"
void
return;
}
void
/* Send cancel for all commands in this group */
}
}
int
mm_command_t *end_cmd) {
char *drive_to_unload = NULL;
char *lib_to_unload = NULL;
/* cmd is the mount command */
/* This code is the same code as is in mm_set_immediate_mount */
/* make a common function?? */
if (mm_mount_candidate_loaded(cmd)) {
"a candidate cartridge is loaded");
} else if (mm_mount_open_drive(cmd)) {
"open drive found");
&lib_to_unload)) {
/* 2 mount time */
/* these mounts need an unmount, then mount */
if (drive_to_unload == NULL &&
lib_to_unload == NULL) {
"drive loaded with non-candidate "
"must unload 1st");
/* Need to set up parent command */
/* return as dispatch depend */
"%s needs unload to complete first",
} else {
"candidate loaded in non-candidate drive "
"must unload 1st");
/* Need to set up parent command */
/* return as dispatch depend */
"%s needs unload to complete first",
}
/* 3 mount time */
/* Candidate cart is mounted, */
/* the only candidate drive is loaded with non-candidate */
/* need to unmount candidate cart, unmount candidate drive */
} else {
"no drives found due to other candidates");
return (MM_BE_BLOCKING);
}
/* May want to add additional arg's to this message? */
"ETMPUNAVAIL",
NULL);
return (MM_BE_ERROR);
}
/* Select Is done - print the results */
"complete for task %s",
mount_info->cmi_dm);
return (MM_BE_DISPATCH);
}
int
mm_command_t *end_cmd) {
char *cur_cartid = NULL;
char *cur_library = NULL;
/* cmd is the unmount command */
"ETMPUNAVAIL",
NULL);
return (MM_BE_BLOCKING);
}
"unmount has no candidates"
" due to other unmount");
return (MM_BE_ERROR);
}
"ETMPUNAVAIL",
NULL);
return (MM_BE_BLOCKING);
}
"unmount has no candidates"
" due to other unmount");
return (MM_BE_ERROR);
}
/* Select Is done - print the results */
"complete for task %s",
mount_info->cmi_dm);
return (MM_BE_DISPATCH);
}
void
/* remove candidates set in set_cmd */
/* from the beginend candidatea list in cmd */
int seen_same = 0;
"remove %s and %s from candidate lists",
/* same command */
seen_same = 1;
continue;
}
if (seen_same == 0) {
continue;
}
cart->cmi_cart_id) == 0) {
}
drive->cmi_drive_name) == 0) {
}
}
}
}
}
void
/* remove candidates set in set_cmd */
/* from the beginend candidatea list in cmd */
int seen_same = 0;
"remove %s and %s from candidate lists",
/* not an unmount */
continue;
}
/* same command */
seen_same = 1;
continue;
}
if (seen_same == 0) {
continue;
}
cart->cmi_cart_id) == 0) {
}
drive->cmi_drive_name) == 0) {
}
}
}
}
}
int
/* not an unmount */
continue;
}
drive_name) == 0) {
return (1);
}
}
return (0);
}
int
/* this function needs to initialize the mount cmd's */
/* in the unmount commands */
/* tm_be_match_mount will match mounts to unmounts */
int cart_rows;
"error getting candidate "
"cartridge");
/* No carts or error */
return (MM_BE_ERROR);
}
if (cart_rows == 0) {
/* No Cartridge Matches Error */
"match statment in mount "
NULL);
return (MM_BE_ERROR);
}
/* Create the list objects for */
db)) {
"error initializing candidate lists");
/* err buf should be set by mm_mount_init */
/* so return and remove */
"error init candidate lists");
return (MM_BE_ERROR);
}
}
"keep only drive candidates selected in unmount cmd");
/* Keep only the drive candidates selected in a unmount command */
/* not an mount */
continue;
}
" check if %s is selected in an unmount",
end_cmd) == 0) {
" remove this drive");
} else {
" keep this drive");
drive->cmi_remove_drive = 0;
}
}
}
}
return (MM_BE_OK);
}
int
/* select the cart drive for this mnt */
char *cur_cartid = NULL;
char *cur_library = NULL;
int found_unmount = 0;
"tm_be_match_mount");
"ETMPUNAVAIL",
NULL);
return (MM_BE_BLOCKING);
}
"mount has no candidates");
return (MM_BE_ERROR);
}
"ETMPUNAVAIL",
NULL);
return (MM_BE_BLOCKING);
}
"mount has no candidates");
return (MM_BE_ERROR);
}
/* Select Is done - print the results */
"complete for task %s",
mount_info->cmi_dm);
/* not an unmount */
continue;
}
/* same drive */
found_unmount = 1;
}
}
if (found_unmount == 0) {
"couldn't find unmount for this mount");
"couldn't find unmount for this mount");
return (MM_BE_ERROR);
}
/* Is this cart currently loaded */
"select \"LibraryName\",\"DriveName\" "
"from \"DRIVE\" where \"DRIVE\"."
"\"CartridgePCL\" = '%s';",
cur_pcl) != MM_DB_DATA) {
"tm_be_match_mount: "
"db error getting drive info");
return (MM_BE_ERROR);
}
/* Cur cart is not loaded */
"%s not found in a drive",
cur_pcl);
} else {
"need to unmount %s, %s "
"before mount ",
if (unmnt_cmd2 == NULL) {
"couldn't find unmount for this mount");
"couldn't find unmount for this mount");
return (MM_BE_ERROR);
}
"unmnt_cmd1->cmd_name == %s (%p)",
"unmnt_cmd2->cmd_name == %s (%p)",
"mnt_cmd->cmd_name == %s (%p)",
}
"mount finished setting up");
return (MM_BE_OK);
}
int
/* This is what the function may return */
/* MM_BE_ERROR */
/* MM_BE_BLOCKING */
/* MM_BE_DISPATCH */
/* For BLOCKING and MMS_ERROR, end cmd error buf */
/* Should be set */
int rc;
"tm_be_pairs");
/* not an unmount */
continue;
}
switch (rc) {
case MM_UNMOUNT_ERROR:
/* Error code should be set */
"internal error, mm_unmount_ready");
return (MM_BE_ERROR);
case MM_UNMOUNT_READY:
"unmount is ready to go, ");
break;
case MM_UNMOUNT_NOT_READY:
/* Error code should be set */
"immediate begin-end group "
"is not ready");
return (MM_BE_ERROR);
}
/* Error code should be set */
"blocking unmount not ready, "
"wait longer and try later");
return (MM_BE_BLOCKING);
default:
"bad rc mm_unmount_ready");
"bad rc mm_unmount_ready");
return (MM_BE_ERROR);
}
}
"unmounts prepared");
/* now determine exactly which tapes to unmount */
/* not an unmount */
continue;
}
if (rc == MM_BE_ERROR) {
/* error set for end command already */
return (MM_BE_ERROR);
} else if (rc == MM_BE_BLOCKING) {
"blocking mount not ready, "
"wait longer and try later");
return (MM_BE_BLOCKING);
}
/* remove cmi_cart and cmi_drive from */
/* above from the remaining */
/* unmount candidates */
}
/* All unmount cmds have been set up */
/* set up each mount using the candidates in unmounts */
/* error set for end command already */
return (MM_BE_ERROR);
}
"mounts initialized");
/* not an mount */
continue;
}
/* tm_be_match_mount will match this */
/* mount with an unmount */
if (rc == MM_BE_ERROR) {
/* error set for end command already */
return (MM_BE_ERROR);
}
}
/* All mounts have been setup, */
/* create the TASK objects */
}
/* Put these mounts on the command queue */
/* All mounts are set and ready to go */
return (MM_BE_DISPATCH);
}
cur);
}
}
int
int rc;
/* Errors */
int mount_has_error = 0;
int mount_would_block = 0;
int only_retry = 1;
int retry_in_use = 1;
/* This is the function can return */
/* MM_BE_ERROR */
/* MM_BE_BLOCKING */
/* MM_BE_DISPATCH */
/* For BLOCKING and MMS_ERROR, end cmd error buf */
/* Should be set */
"tm_be_mounts");
/* Instead of returning set mount_has_error or mount_would_block */
/* After calling for ever mount generate the correct error code */
switch (rc) {
case MM_MOUNT_ERROR:
/* Error code should be set */
"internal error, tm_be_mount_ready");
mount_has_error = 1;
break;
case MM_MOUNT_READY:
/* The mount is ready, mount_info should be set */
/* continue to state 1 */
"mount is ready to go ");
break;
case MM_MOUNT_NEED_UNLOAD:
/* this immediate mount needs to */
/* wait for an unload */
"mount needs to wait "
"for unload to complete");
break;
case MM_MOUNT_NOT_READY:
/* Error code should be set */
"immediate begin-end group "
"is not ready");
mount_has_error = 1;
break;
}
/* Error code should be set */
"blocking mount not ready, "
"wait longer and try later");
mount_would_block = 1;
break;
default:
"bad rc mm_mount_ready");
"bad rc mm_mount_ready");
return (MM_BE_ERROR);
}
}
/* Determine the correct error code to use for the end command */
/* Each mount in the group with an error will have ecode and eclass */
if (mount_has_error) {
"at least one mount had "
"an error for this begin-end");
/* Check every command's error class */
/* If there are only retry errors use the retry class */
/* found a mount where class is not retry */
only_retry = 0;
ECLASS_RETRY) == 0)) {
/* This is a retry class */
/* Check if this is an inuse error */
"EDRVINUSE") == 0) ||
"ECARTINUSE") == 0)) {
retry_in_use = 1;
}
}
ECLASS_INTERNAL) == 0)) {
/* This mount had a system error */
/* Set system error and return */
"internal error processing "
"a begin-end mount cmd");
return (MM_BE_ERROR);
}
}
if (only_retry) {
"all mounts have retry error class ");
if (retry_in_use) {
"at least one mount "
"has an in-use error");
/* Set error for retry */
"ETMPINUSE",
NULL);
} else {
/* Set error for retry */
"ETMPUNAVAIL",
NULL);
}
} else {
"at least one mount had a eclass"
" more severe than retry ");
/* One or more mount has errors */
/* that are non retry */
"ENOSOLUTIONS",
NULL);
}
return (MM_BE_ERROR);
}
if (mount_would_block) {
"at least one mount has "
"to block for this begin-end");
return (MM_BE_BLOCKING);
}
/* Mount candidate lists have been set up, */
/* divide the resources and set up the exact */
if (rc == MM_BE_ERROR) {
/* error set for end command already */
return (MM_BE_ERROR);
} else if (rc == MM_BE_BLOCKING) {
"blocking mount not ready, "
"wait longer and try later");
return (MM_BE_BLOCKING);
}
/* remove cmi_cart and cmi_drive from */
/* above from the remaining */
/* unmount candidates */
}
/* Need to remove all dispatch releated stuff from the functions */
/* used by tm_be_set_mount or mm_set_immediate_mount */
/* error should be set */
"error setting up mount for dispatch");
}
}
/* All mounts have been setup, */
/* create the TASK objects */
}
/* Put these mounts on the command queue */
/* All mounts are set and ready to go */
return (MM_BE_DISPATCH);
}
int
int unmount_count = 0;
int mount_count = 0;
int print_message = 1;
/* Returns 1 if this has unmounts */
/* Also makes sure unmounts are paird with mounts */
if (print_message)
"tm_be_cmd_has_unmounts");
if (print_message)
"saw a mount");
mount_count ++;
if (print_message)
"saw an unmount");
unmount_count ++;
}
}
if (unmount_count == 0)
return (0);
if (unmount_count == mount_count)
return (1);
"num mounts does not match num unmounts");
return (-1);
}
int
{
int rc;
int immediate = 0;
int unmount = 0;
immediate = 1;
/* Determine the begin-end type */
/* Currently there are 2 types */
/* 1. A group of all mounts */
/* Error buf is set */
goto cmd_error;
}
if (unmount == 1) {
} else {
}
switch (rc) {
case MM_BE_BLOCKING:
if (immediate)
goto cmd_error;
return (0);
case MM_BE_DISPATCH:
/* Send success for end */
return (1);
case MM_BE_ERROR:
/* Error buf is set */
goto cmd_error;
}
/* Error buf must be set */
return (0);
}
int
{
/* Find the command associated with this task */
/* task id matches */
break;
}
}
task_id);
return (0);
}
if (cur_cmd->cmd_remove) {
/* This command has already been marked for removal */
/* skip and let main thread clean it up */
"skip %s, marked for remove",
return (0);
}
/* Set cmd_dispatchable inside this func */
return (1);
}
return (0);
/* set command as dispatchable */
return (1);
}
return (0);
/* set command as dispatchable */
return (1);
}
} else {
return (0);
}
return (0);
}
int
{
int num_tasks;
int num_dispatched = 0;
int i;
/* used when a mount needs a drive unloaded 1st */
/* Get ordered list of blocked tasks */
"select * from "
"(select \"TaskID\","
"\"TaskPriority\" from \"TASK\" "
"where \"TaskState\" = 'blocked' "
"order by \"TaskArrivalTime\") "
"as foo order by \"TaskPriority\" "
"desc;") != MM_DB_DATA) {
"mm_get_tm_cmd: "
"db error getting task info");
return (1);
}
if (num_tasks == 0) {
mm_clear_db(&tasks);
return (0);
}
for (i = 0; i < num_tasks; i++) {
/* Try to dispatch each task */
PQgetvalue(tasks, i, 0),
mm_data) == 1) {
/* Task ok for dispatch */
PQgetvalue(tasks, i, 0));
num_dispatched ++;
} else {
/* Resources not available */
PQgetvalue(tasks, i, 0));
}
}
if (num_dispatched == 0) {
mm_clear_db(&tasks);
return (0);
}
/* wakeup worker thread to do work */
mm_clear_db(&tasks);
return (0);
}
{
}
{
char *cmd_text;
return (MM_DB_ERROR); /* out of memory */
}
"(\"TaskID\", \"TaskType\", \"ApplicationName\", "
"\"AIName\", \"TaskStatement\", \"ClientTaskID\", "
"\"TaskState\") VALUES "
"('%s', '%s', '%s', '%s', $$%s$$, '%s', '%s')",
return (rc);
}
{
"select * from \"TASKCARTRIDGE\" where "
"\"TaskID\" = '%s' and \"CartridgeID\" = '%s'",
if (rc != MM_DB_DATA) {
"mm_set_tm_cartridge: "
"db error getting info for"
" TASKCARTRIDGE");
return (rc);
}
if (PQntuples(task_results) == 0) {
"(\"TaskID\", \"CartridgeID\") VALUES ('%s', '%s')",
"mm_set_tm_cartridge: "
"db error inserting TASKCARTRIDGE");
}
} else {
if (rc == MM_DB_DATA) {
}
}
return (rc);
}
{
"select * from \"TASKDRIVE\" where "
"\"TaskID\" = '%s' and \"DriveName\" = '%s'",
if (rc != MM_DB_DATA) {
"mm_set_tm_drive: "
"db error getting info for"
" TASKDRIVE");
return (rc);
}
if (PQntuples(task_results) == 0) {
"(\"TaskID\", \"DriveName\") VALUES ('%s', '%s')",
"mm_set_tm_drive: "
"db error inserting TASKDRIVE");
}
} else {
if (rc == MM_DB_DATA) {
}
}
return (rc);
}
{
"select * from \"TASKLIBRARY\" where "
"\"TaskID\" = '%s' and \"LibraryName\" = '%s'",
if (rc != MM_DB_DATA) {
"mm_set_tm_library: "
"db error getting info for"
" TASKLIBRARY");
return (rc);
}
if (PQntuples(task_results) == 0) {
"(\"TaskID\", \"LibraryName\") VALUES ('%s', '%s')",
"mm_set_tm_library: "
"db error inserting TASKLIBRARY");
}
} else {
if (rc == MM_DB_DATA) {
}
}
return (rc);
}
{
"SET \"TaskState\" = 'dispatched' "
"WHERE \"TaskID\" = '%s'", taskid);
return (rc);
}
{
"WHERE \"TaskID\" = '%s'", taskid);
"mm_del_tm_cmd: "
"db error deleteing from TASK");
}
"\"RequestingTaskID\" = '%s' and "
"\"RequestState\" != 'responded';", taskid);
"mm_del_tm_cmd: "
"db error deleteing from REQUEST");
}
return (rc);
}
{
"SET \"TaskPriority\" = '%s' "
return (rc);
}