Exemple #1
0
bool BaseResource::Invalidate () {

    ClassAd ad;
    
    /* Set the correct types */
    SetMyTypeName ( ad, GRID_ADTYPE );

    /* We only want to invalidate this resource. Using the tuple
       (HashName,SchedName,Owner) as unique id. */
	std::string line;
	formatstr( line,
        "((TARGET.%s =?= \"%s\") && (TARGET.%s =?= \"%s\") && "
		 "(TARGET.%s =?= \"%s\") && (TARGET.%s =?= \"%s\"))",
        ATTR_HASH_NAME, GetHashName (),
        ATTR_SCHEDD_NAME, ScheddObj->name (),
		ATTR_SCHEDD_IP_ADDR, ScheddObj->addr (),
        ATTR_OWNER, myUserName );
    ad.AssignExpr ( ATTR_REQUIREMENTS, line.c_str() );

	ad.Assign( ATTR_HASH_NAME, GetHashName() );
	ad.Assign( ATTR_SCHEDD_NAME, ScheddObj->name() );
	ad.Assign( ATTR_SCHEDD_IP_ADDR, ScheddObj->addr() );
	ad.Assign( ATTR_OWNER, myUserName );

    dprintf (
        D_FULLDEBUG,
        "BaseResource::InvalidateResource: \n%s\n",
        line.c_str() );
    
	return daemonCore->sendUpdates( INVALIDATE_GRID_ADS, &ad, NULL, true ) > 0;
}
/* Function   : finalizeDelta
 * Description: clears and resets all inner structures and data members declared
 *				in this class only (excluding inherited classes)
 */
void
ReplicatorStateMachine::finalizeDelta( )
{
    ClassAd invalidate_ad;
    MyString line;

    dprintf( D_ALWAYS, "ReplicatorStateMachine::finalizeDelta started\n" );
    utilCancelTimer(m_replicationTimerId);
    utilCancelTimer(m_versionRequestingTimerId);
    utilCancelTimer(m_versionDownloadingTimerId);
    utilCancelTimer(m_updateCollectorTimerId);
    m_replicationInterval               = -1;
    m_hadAliveTolerance                 = -1;
    m_maxTransfererLifeTime             = -1;
    m_newlyJoinedWaitingVersionInterval = -1;
    m_lastHadAliveTime                  = -1;
    m_updateInterval                    = -1;

    if ( m_classAd != NULL ) {
        delete m_classAd;
        m_classAd = NULL;
    }

    SetMyTypeName( invalidate_ad, QUERY_ADTYPE );
    SetTargetTypeName( invalidate_ad, "Replication" );
    line.formatstr( "TARGET.%s == \"%s\"", ATTR_NAME, m_name.Value( ) );
    invalidate_ad.AssignExpr( ATTR_REQUIREMENTS, line.Value( ) );
	invalidate_ad.Assign( ATTR_NAME, m_name.Value() );
    daemonCore->sendUpdates( INVALIDATE_ADS_GENERIC, &invalidate_ad, NULL, false );
}
Exemple #3
0
static void
serialize_input( void )
{

	char sinful[16 + 10];
	int  found_eof		= 0,
		 found_error	= 0,
		 empty			= 0;

	/**	Determine if we are using the command-line options, a file,
		or standard input as input */
	if ( !stdio ) {

		/**	Contrive a sinful string based on our IP address */
		sprintf ( sinful, "<255.255.255.255:1234>" );

		/**	We were give all the raw data, so we're going to create
			a fake machine ad that we will use when invoking the waking
			mechanism */
		ad = new ClassAd ();
		SetMyTypeName ( *ad, STARTD_ADTYPE );
		SetTargetTypeName ( *ad, JOB_ADTYPE );
		ad->Assign ( ATTR_HARDWARE_ADDRESS, mac );
		ad->Assign ( ATTR_SUBNET_MASK, mask );
		ad->Assign ( ATTR_MY_ADDRESS, sinful );
		ad->Assign ( ATTR_WOL_PORT, port );

	} else {

		/**	Open the machine ad file or read it from stdin */
		if ( fn_in && *fn_in ) {
			in = safe_fopen_wrapper ( fn_in, "r" );
		} else {
			in = stdin;
			fn_in = "<stdin>";
		}

		if ( !in ) {
			error ( E_FOPEN, fn_in, strerror ( errno ), errno );
		}

		/**	Serialize the machine ad from a file */
		ad = new ClassAd (
			in,
			"?$#%^&*@", /* sufficiently random garbage? */
			found_eof,
			found_error,
			empty );

		if ( found_error ) {
			error (
				E_CLASSAD,
				found_error );
		}

	}

}
Exemple #4
0
void
Defrag::invalidatePublicAd() {
	ClassAd invalidate_ad;
	std::string line;

	SetMyTypeName(invalidate_ad, QUERY_ADTYPE);
	SetTargetTypeName(invalidate_ad, "Defrag");

	formatstr(line,"%s == \"%s\"", ATTR_NAME, m_daemon_name.c_str());
	invalidate_ad.AssignExpr(ATTR_REQUIREMENTS, line.c_str());
	invalidate_ad.Assign(ATTR_NAME, m_daemon_name.c_str());
	daemonCore->sendUpdates(INVALIDATE_ADS_GENERIC, &invalidate_ad, NULL, false);
}
Exemple #5
0
void
DBMSManager::InvalidatePublicAd() {
    ClassAd query_ad;
    SetMyTypeName(query_ad, QUERY_ADTYPE);
    SetTargetTypeName(query_ad, DBMSD_ADTYPE);

    MyString line;
    line.formatstr("%s = TARGET.%s == \"%s\"", ATTR_REQUIREMENTS, ATTR_NAME, m_name.Value());
    query_ad.Insert(line.Value());
    query_ad.Assign(ATTR_NAME,m_name.Value());

    m_collectors->sendUpdates(INVALIDATE_ADS_GENERIC, &query_ad, NULL, true);

    //TODO/FIXME - delete the ads of the databases we're advertising

    return;
}
Exemple #6
0
void
DBMSManager::InitPublicAd() {
    m_public_ad = ClassAd();

    //TODO: this is the wrong ADTYPE.
    //Use the new generic ad type when it becomes available.
    //Until then, actual writes to the collector are disabled,
    //because it conflicts with the schedd on the same host..

    SetMyTypeName( m_public_ad, DBMSD_ADTYPE );
    SetTargetTypeName( m_public_ad, "" );

    m_public_ad.Assign(ATTR_MACHINE,get_local_fqdn());
    m_public_ad.Assign(ATTR_NAME,m_name.Value());

    config_fill_ad( &m_public_ad );
}
Exemple #7
0
int
LogNewClassAd::Play(void *data_structure)
{
	int result;
	ClassAdHashTable *table = (ClassAdHashTable *)data_structure;
	ClassAd	*ad = new ClassAd();
	SetMyTypeName(*ad, mytype);
	SetTargetTypeName(*ad, targettype);
	ad->EnableDirtyTracking();
	result = table->insert(HashKey(key), ad);

#if defined(HAVE_DLOPEN)
	ClassAdLogPluginManager::NewClassAd(key);
#endif

	return result;
}
Exemple #8
0
void
Defrag::publish(ClassAd *ad)
{
	char *valid_name = build_valid_daemon_name(m_defrag_name.c_str());
	ASSERT( valid_name );
	m_daemon_name = valid_name;
	delete [] valid_name;

	SetMyTypeName(*ad, "Defrag");
	SetTargetTypeName(*ad, "");

	ad->Assign(ATTR_NAME,m_daemon_name.c_str());

	m_stats.Tick();
	m_stats.Publish(*ad);
	daemonCore->publish(ad);
}
void
ReplicatorStateMachine::initializeClassAd()
{
    if( m_classAd != NULL) {
        delete m_classAd;
        m_classAd = NULL;
    }

    m_classAd = new ClassAd();

    SetMyTypeName(*m_classAd, "Replication");
    SetTargetTypeName(*m_classAd, "");

    m_name.formatstr( "replication@%s -p %d", get_local_fqdn().Value(),
				  daemonCore->InfoCommandPort( ) );
    m_classAd->Assign( ATTR_NAME, m_name.Value( ) );
    m_classAd->Assign( ATTR_MY_ADDRESS,
					   daemonCore->InfoCommandSinfulString( ) );

    // publish list of replication nodes
    char* buffer = param( "REPLICATION_LIST" );
	if ( NULL == buffer ) {
		EXCEPT( "ReplicatorStateMachine: No replication list!!" );
	}
    char* replAddress = NULL;
    StringList replList;
    MyString attrReplList;
    MyString comma;

    replList.initializeFromString( buffer );
    replList.rewind( );

    while( ( replAddress = replList.next() ) ) {
        attrReplList += comma;
        attrReplList += replAddress;
        comma = ",";
    }
    m_classAd->Assign( ATTR_REPLICATION_LIST, attrReplList.Value( ) );

    // publish DC attributes
    daemonCore->publish(m_classAd);
	free(buffer);
}
Exemple #10
0
void
invalidate_ads() {
	ClassAd cmd_ad;
	SetMyTypeName( cmd_ad, QUERY_ADTYPE );
	SetTargetTypeName( cmd_ad, MASTER_ADTYPE );
	
	MyString line;
	std::string escaped_name;
	char* default_name = ::strnewp(MasterName);
	if(!default_name) {
		default_name = default_daemon_name();
	}
	
	EscapeAdStringValue( default_name, escaped_name );
	line.formatstr( "( TARGET.%s == \"%s\" )", ATTR_NAME, escaped_name.c_str() );
	cmd_ad.AssignExpr( ATTR_REQUIREMENTS, line.Value() );
	cmd_ad.Assign( ATTR_NAME, default_name );
	cmd_ad.Assign( ATTR_MY_ADDRESS, daemonCore->publicNetworkIpAddr());
	daemonCore->sendUpdates( INVALIDATE_MASTER_ADS, &cmd_ad, NULL, false );
	delete [] default_name;
}
Exemple #11
0
bool BaseResource::SendUpdate () {

    ClassAd ad;

	/* Set the correct types */
    SetMyTypeName ( ad, GRID_ADTYPE );

    /* populate class ad with the relevant resource information */
    PublishResourceAd ( &ad );

	daemonCore->publish( &ad );

	std::string tmp;
    sPrintAd ( tmp, ad );
    dprintf (
        D_FULLDEBUG,
        "BaseResource::UpdateResource: \n%s\n",
        tmp.c_str() );

	return daemonCore->sendUpdates( UPDATE_GRID_AD, &ad, NULL, true ) > 0;
}
Exemple #12
0
ClassAd * ProcAd::dumpToAd( piPTR pi ) {

  char line[128];
  ClassAd *ad = new ClassAd;

  SetMyTypeName( *ad, "PROCESS_INFORMATION" );
  SetTargetTypeName( *ad, "ENQUIRING_MINDS_WANT_TO_KNOW" );

  sprintf ( line, "THIS_PID = %d", pi->pid );
  ad->Insert(line);
  sprintf ( line, "PARENT_PID = %ld", (long)pi->ppid );
  ad->Insert(line);
  sprintf ( line, "IMAGE_SIZE = %ld", (long)pi->imgsize );
  ad->Insert(line);
  sprintf ( line, "RESIDENT_SET_SIZE = %ld", (long)pi->rssize );
  ad->Insert(line);
#if HAVE_PSS
  if( pi->pssize_available ) {
	  sprintf ( line, "PROPORTIONAL_SET_SIZE = %ld", (long)pi->pssize );
	  ad->Insert(line);
  }
#endif
  sprintf ( line, "MAJOR_PAGE_FAULTS = %ld", (long)pi->majfault );
  ad->Insert(line);
  sprintf ( line, "MINOR_PAGE_FAULTS = %ld", (long)pi->minfault );
  ad->Insert(line);
  sprintf ( line, "USER_TIME = %ld", (long)pi->user_time );
  ad->Insert(line);
  sprintf ( line, "SYSTEM_TIME = %ld", (long)pi->sys_time );
  ad->Insert(line);
  sprintf ( line, "PROCESS_AGE = %ld", (long)pi->age );
  ad->Insert(line);
  sprintf ( line, "PERCENT_CPU_USAGE = %6.2f",  pi->cpuusage );
  ad->Insert(line);

  return ad;
}
Exemple #13
0
void
init_classad()
{
	if( ad ) delete( ad );
	ad = new ClassAd();

	SetMyTypeName(*ad, MASTER_ADTYPE);
	SetTargetTypeName(*ad, "");

	if (MasterName) {
		ad->Assign(ATTR_NAME, MasterName);
	} else {
		char* default_name = default_daemon_name();
		if( ! default_name ) {
			EXCEPT( "default_daemon_name() returned NULL" );
		}
		ad->Assign(ATTR_NAME, default_name);
		delete [] default_name;
	}

#if !defined(WIN32)
	ad->Assign(ATTR_REAL_UID, (int)getuid());
#endif
}
Exemple #14
0
QueryResult CondorQuery::
getQueryAd (ClassAd &queryAd)
{
	QueryResult	result;
	ExprTree *tree;

	queryAd = extraAttrs;
	if (resultLimit > 0) { queryAd.Assign(ATTR_LIMIT_RESULTS, resultLimit); }

	result = (QueryResult) query.makeQuery (tree);
	if (result != Q_OK) return result;
	queryAd.Insert(ATTR_REQUIREMENTS, tree);

	// fix types
	SetMyTypeName (queryAd, QUERY_ADTYPE);
	switch (queryType) {

	  case DEFRAG_AD:
		SetTargetTypeName(queryAd, DEFRAG_ADTYPE);
		break;
	  case STARTD_AD:
	  case STARTD_PVT_AD:
		SetTargetTypeName (queryAd, STARTD_ADTYPE);
		break;

	  case SCHEDD_AD:
		SetTargetTypeName (queryAd, SCHEDD_ADTYPE);
		break;

	  case SUBMITTOR_AD:
		SetTargetTypeName (queryAd, SUBMITTER_ADTYPE);
		break;

	  case LICENSE_AD:
		SetTargetTypeName (queryAd, LICENSE_ADTYPE);
		break;

	  case MASTER_AD:
		SetTargetTypeName (queryAd, MASTER_ADTYPE);
		break;

	  case CKPT_SRVR_AD:
		SetTargetTypeName (queryAd, CKPT_SRVR_ADTYPE);
		break;

	  case COLLECTOR_AD:
		SetTargetTypeName (queryAd, COLLECTOR_ADTYPE);
		break;

	  case NEGOTIATOR_AD:
		SetTargetTypeName (queryAd, NEGOTIATOR_ADTYPE);
		break;

      case STORAGE_AD:
        SetTargetTypeName (queryAd, STORAGE_ADTYPE);
        break;

      case CREDD_AD:
        SetTargetTypeName (queryAd, CREDD_ADTYPE);
        break;

	  case GENERIC_AD:
		if ( genericQueryType ) {
			SetTargetTypeName (queryAd, genericQueryType);
		} else {
			SetTargetTypeName (queryAd, GENERIC_ADTYPE);
		}
		break;

	  case ANY_AD:
		SetTargetTypeName (queryAd, ANY_ADTYPE);
		break;

	  case DATABASE_AD:
		SetTargetTypeName (queryAd, DATABASE_ADTYPE);
		break;

	  case TT_AD:
		SetTargetTypeName (queryAd, TT_ADTYPE);
		break;

      case GRID_AD:
        SetTargetTypeName (queryAd, GRID_ADTYPE);
        break;

	  case HAD_AD:
		SetTargetTypeName (queryAd, HAD_ADTYPE);
		break;

	  case ACCOUNTING_AD:
		SetTargetTypeName(queryAd, ACCOUNTING_ADTYPE);
		break;
	  default:
		return Q_INVALID_QUERY;
	}

	return Q_OK;
}
Exemple #15
0
QueryResult CondorQuery::
getQueryAd (ClassAd &queryAd)
{
	QueryResult	result;
	ExprTree *tree;

	queryAd = extraAttrs;

	result = (QueryResult) query.makeQuery (tree);
	if (result != Q_OK) return result;
	queryAd.Insert(ATTR_REQUIREMENTS, tree);

	// fix types
	SetMyTypeName (queryAd, QUERY_ADTYPE);
	switch (queryType) {
#ifdef HAVE_EXT_POSTGRESQL
	  case QUILL_AD:
		SetTargetTypeName (queryAd, QUILL_ADTYPE);
		break;
#endif /* HAVE_EXT_POSTGRESQL */

	  case DEFRAG_AD:
		SetTargetTypeName(queryAd, DEFRAG_ADTYPE);
		break;
	  case STARTD_AD:
	  case STARTD_PVT_AD:
		SetTargetTypeName (queryAd, STARTD_ADTYPE);
		break;

	  case SCHEDD_AD:
		SetTargetTypeName (queryAd, SCHEDD_ADTYPE);
		break;

	  case SUBMITTOR_AD:
		SetTargetTypeName (queryAd, SUBMITTER_ADTYPE);
		break;

	  case LICENSE_AD:
		SetTargetTypeName (queryAd, LICENSE_ADTYPE);
		break;

	  case MASTER_AD:
		SetTargetTypeName (queryAd, MASTER_ADTYPE);
		break;

	  case CKPT_SRVR_AD:
		SetTargetTypeName (queryAd, CKPT_SRVR_ADTYPE);
		break;

	  case COLLECTOR_AD:
		SetTargetTypeName (queryAd, COLLECTOR_ADTYPE);
		break;

	  case NEGOTIATOR_AD:
		SetTargetTypeName (queryAd, NEGOTIATOR_ADTYPE);
		break;

      case STORAGE_AD:
        SetTargetTypeName (queryAd, STORAGE_ADTYPE);
        break;

      case CREDD_AD:
        SetTargetTypeName (queryAd, CREDD_ADTYPE);
        break;

	  case GENERIC_AD:
		if ( genericQueryType ) {
			SetTargetTypeName (queryAd, genericQueryType);
		} else {
			SetTargetTypeName (queryAd, GENERIC_ADTYPE);
		}
		break;

      case XFER_SERVICE_AD:
        SetTargetTypeName (queryAd, XFER_SERVICE_ADTYPE);
        break;

      case LEASE_MANAGER_AD:
        SetTargetTypeName (queryAd, LEASE_MANAGER_ADTYPE);
        break;

	  case ANY_AD:
		SetTargetTypeName (queryAd, ANY_ADTYPE);
		break;

	  case DATABASE_AD:
		SetTargetTypeName (queryAd, DATABASE_ADTYPE);
		break;

	  case DBMSD_AD:
		SetTargetTypeName (queryAd, DBMSD_ADTYPE);
		break;

	  case TT_AD:
		SetTargetTypeName (queryAd, TT_ADTYPE);
		break;

      case GRID_AD:
        SetTargetTypeName (queryAd, GRID_ADTYPE);
        break;

	  case HAD_AD:
		SetTargetTypeName (queryAd, HAD_ADTYPE);
		break;

	  default:
		return Q_INVALID_QUERY;
	}

	return Q_OK;
}
Exemple #16
0
/* Utility function to create a generic job ad. The caller can then fill
 * in the relevant details.
 */
ClassAd *CreateJobAd( const char *owner, int universe, const char *cmd )
{
	ClassAd *job_ad = new ClassAd();

	SetMyTypeName(*job_ad, JOB_ADTYPE);
	SetTargetTypeName(*job_ad, STARTD_ADTYPE);

	if ( owner ) {
		job_ad->Assign( ATTR_OWNER, owner );
	} else {
		job_ad->AssignExpr( ATTR_OWNER, "Undefined" );
	}
	job_ad->Assign( ATTR_JOB_UNIVERSE, universe );
	job_ad->Assign( ATTR_JOB_CMD, cmd );

	job_ad->Assign( ATTR_Q_DATE, (int)time(NULL) );
	job_ad->Assign( ATTR_COMPLETION_DATE, 0 );

	job_ad->Assign( ATTR_JOB_REMOTE_WALL_CLOCK, 0.0 );
	job_ad->Assign( ATTR_JOB_LOCAL_USER_CPU, 0.0 );
	job_ad->Assign( ATTR_JOB_LOCAL_SYS_CPU, 0.0 );
	job_ad->Assign( ATTR_JOB_REMOTE_USER_CPU, 0.0 );
	job_ad->Assign( ATTR_JOB_REMOTE_SYS_CPU, 0.0 );

		// This is a magic cookie, see how condor_submit sets it
	job_ad->Assign( ATTR_CORE_SIZE, -1 );

		// Are these ones really necessary?
	job_ad->Assign( ATTR_JOB_EXIT_STATUS, 0 );
	job_ad->Assign( ATTR_ON_EXIT_BY_SIGNAL, false );

	job_ad->Assign( ATTR_NUM_CKPTS, 0 );
	job_ad->Assign( ATTR_NUM_JOB_STARTS, 0 );
	job_ad->Assign( ATTR_NUM_RESTARTS, 0 );
	job_ad->Assign( ATTR_NUM_SYSTEM_HOLDS, 0 );
	job_ad->Assign( ATTR_JOB_COMMITTED_TIME, 0 );
	job_ad->Assign( ATTR_CUMULATIVE_SLOT_TIME, 0 );
	job_ad->Assign( ATTR_COMMITTED_SLOT_TIME, 0 );
	job_ad->Assign( ATTR_TOTAL_SUSPENSIONS, 0 );
	job_ad->Assign( ATTR_LAST_SUSPENSION_TIME, 0 );
	job_ad->Assign( ATTR_CUMULATIVE_SUSPENSION_TIME, 0 );
	job_ad->Assign( ATTR_COMMITTED_SUSPENSION_TIME, 0 );

	job_ad->Assign( ATTR_JOB_ROOT_DIR, "/" );

	job_ad->Assign( ATTR_MIN_HOSTS, 1 );
	job_ad->Assign( ATTR_MAX_HOSTS, 1 );
	job_ad->Assign( ATTR_CURRENT_HOSTS, 0 );

	job_ad->Assign( ATTR_WANT_REMOTE_SYSCALLS, false );
	job_ad->Assign( ATTR_WANT_CHECKPOINT, false );
	job_ad->Assign( ATTR_WANT_REMOTE_IO, true );

	job_ad->Assign( ATTR_JOB_STATUS, IDLE );
	job_ad->Assign( ATTR_ENTERED_CURRENT_STATUS, (int)time(NULL) );

	job_ad->Assign( ATTR_JOB_PRIO, 0 );
	job_ad->Assign( ATTR_NICE_USER, false );

	job_ad->Assign( ATTR_JOB_NOTIFICATION, NOTIFY_NEVER );

	

	job_ad->Assign( ATTR_IMAGE_SIZE, 100 );

	job_ad->Assign( ATTR_JOB_IWD, "/tmp" );
	job_ad->Assign( ATTR_JOB_INPUT, NULL_FILE );
	job_ad->Assign( ATTR_JOB_OUTPUT, NULL_FILE );
	job_ad->Assign( ATTR_JOB_ERROR, NULL_FILE );

		// Not sure what to do with these. If stdin/out/err is unset in the
		// submit file, condor_submit sets In/Out/Err to the NULL_FILE and
		// these transfer attributes to false. Otherwise, it leaves the
		// transfer attributes unset (which is treated as true). If we
		// explicitly set these to false here, our caller needs to reset
		// them to true if it changes In/Out/Err and wants the default
		// behavior of transfering them. This will probably be a common
		// oversite. Leaving them unset should be safe if our caller doesn't
		// change In/Out/Err.
	//job_ad->Assign( ATTR_TRANSFER_INPUT, false );
	//job_ad->Assign( ATTR_TRANSFER_OUTPUT, false );
	//job_ad->Assign( ATTR_TRANSFER_ERROR, false );
	//job_ad->Assign( ATTR_TRANSFER_EXECUTABLE, false );

	job_ad->Assign( ATTR_BUFFER_SIZE, 512*1024 );
	job_ad->Assign( ATTR_BUFFER_BLOCK_SIZE, 32*1024 );

	job_ad->Assign( ATTR_SHOULD_TRANSFER_FILES,
					getShouldTransferFilesString( STF_YES ) );
	job_ad->Assign( ATTR_WHEN_TO_TRANSFER_OUTPUT,
					getFileTransferOutputString( FTO_ON_EXIT ) );

	job_ad->Assign( ATTR_REQUIREMENTS, true );

	job_ad->Assign( ATTR_PERIODIC_HOLD_CHECK, false );
	job_ad->Assign( ATTR_PERIODIC_REMOVE_CHECK, false );
	job_ad->Assign( ATTR_PERIODIC_RELEASE_CHECK, false );

	job_ad->Assign( ATTR_ON_EXIT_HOLD_CHECK, false );
	job_ad->Assign( ATTR_ON_EXIT_REMOVE_CHECK, true );

	job_ad->Assign( ATTR_JOB_ARGUMENTS1, "" );

	job_ad->Assign( ATTR_JOB_LEAVE_IN_QUEUE, false );

	job_ad->AssignExpr( ATTR_REQUEST_MEMORY, "ifthenelse(MemoryUsage isnt undefined,MemoryUsage,( ImageSize + 1023 ) / 1024)" );
	job_ad->AssignExpr( ATTR_REQUEST_DISK, "DiskUsage" );
	job_ad->Assign( ATTR_DISK_USAGE, 1 );
	job_ad->Assign( ATTR_REQUEST_CPUS, 1 );

	// Without these, the starter will not automatically remap the stdout/err (look at sha 422735d9)
	// and possibly won't put them in the correct directory.
	job_ad->Assign( ATTR_STREAM_OUTPUT, false );
	job_ad->Assign( ATTR_STREAM_ERROR, false );

	job_ad->Assign( ATTR_VERSION, CondorVersion() );
	job_ad->Assign( ATTR_PLATFORM, CondorPlatform() );

	job_ad->Assign( ATTR_Q_DATE, time(NULL) );

	return job_ad;
}
Exemple #17
0
void
XferSummary::time_out(time_t now, char *hostaddr)
{
	ClassAd	   	info;
	char		line[128], *tmp;
	char		*str = NULL;

	SetMyTypeName(info, "CkptServer");
	SetTargetTypeName(info, "CkptFile");

	sprintf(line, "%s = \"%s\"", ATTR_NAME, get_local_fqdn().Value());
	info.Insert(line);
    sprintf(line, "%s = \"%s\"", ATTR_MACHINE, hostaddr );
	info.Insert(line);
	sprintf(line, "%s = \"%s\"", ATTR_VERSION, CondorVersion() );
	info.Insert(line);
	sprintf(line, "%s = \"%s\"", ATTR_PLATFORM, CondorPlatform() );
	info.Insert(line);
	sprintf(line, "NumSends = %d", num_sends);
	info.Insert(line);
	sprintf(line, "BytesSent = %d", (int) bytes_sent);
	info.Insert(line);
	sprintf(line, "TimeSending = %d", time_sending);
	info.Insert(line);
	sprintf(line, "AvgSendBandwidth = %f", num_sends ?
			tot_send_bandwidth / num_sends : 0.0);
	info.Insert(line);
	sprintf(line, "NumRecvs = %d", num_recvs);
	info.Insert(line);
	sprintf(line, "BytesReceived = %d", (int) bytes_recv);
	info.Insert(line);
	sprintf(line, "TimeReceiving = %d", time_recving);
	info.Insert(line);
	sprintf(line, "AvgReceiveBandwidth = %f", num_recvs ?
			tot_recv_bandwidth / num_recvs : 0.0);
	info.Insert(line);

	/* ctime adds a newline at the end of the ascii conversion.... */
	str = ctime(&start_time);
	sprintf(line, "CkptServerIntervalStart = \"%s\"", str ? str : "Unknown\n");
	tmp = strchr( line, '\n' );
	if (tmp != NULL) {
		/* delete the newline */
		*tmp = '\"';
		tmp++;
		*tmp = '\0';
	}
	info.Insert(line);

	/* ctime adds a newline at the end of the ascii conversion.... */
	str = ctime(&now);
	sprintf(line, "CkptServerIntervalEnd = \"%s\"", str ? str : "Unknown\n");
	tmp = strchr( line, '\n' );
	if (tmp != NULL) {
		/* delete the newline */
		*tmp = '\"';
		tmp++;
		*tmp = '\0';
	}
	info.Insert(line);

	info.Assign("Disk", sysapi_disk_space(pwd.Value()));
	
	// Send to collector
	if ( Collectors ) {
        dprintf(D_NETWORK, "Sending CkptServer ClassAd:\n");
        dPrintAd(D_NETWORK, info);
		Collectors->sendUpdates (UPDATE_CKPT_SRVR_AD, &info, NULL, true);
	}

	init();
}
Exemple #18
0
void
Starter::exited(int status)
{
	ClassAd *jobAd = NULL;
	bool jobAdNeedsFree = true;

	if (s_claim && s_claim->ad()) {
		// real jobs in the startd have claims and job ads, boinc and perhaps others won't
		jobAd = s_claim->ad();
		jobAdNeedsFree = false;
	} else {
		// Dummy up an ad
		int now = (int) time(0);
		jobAd = new ClassAd();
		SetMyTypeName(*jobAd, "Job");
		SetTargetTypeName(*jobAd, "Machine");
		jobAd->Assign(ATTR_CLUSTER_ID, now);
		jobAd->Assign(ATTR_PROC_ID, 1);
		jobAd->Assign(ATTR_OWNER, "boinc");
		jobAd->Assign(ATTR_Q_DATE, (int)s_birthdate);
		jobAd->Assign(ATTR_JOB_PRIO, 0);
		jobAd->Assign(ATTR_IMAGE_SIZE, 0);
		jobAd->Assign(ATTR_JOB_CMD, "boinc");
		MyString gjid;
		gjid.formatstr("%s#%d#%d#%d", get_local_hostname().Value(), 
					 now, 1, now);
		jobAd->Assign(ATTR_GLOBAL_JOB_ID, gjid);
	}

	// First, patch up the ad a little bit 
	jobAd->Assign(ATTR_COMPLETION_DATE, (int)time(0));
	int runtime = time(0) - s_birthdate;
	
	jobAd->Assign(ATTR_JOB_REMOTE_WALL_CLOCK, runtime);
	int jobStatus = COMPLETED;
	if (WIFSIGNALED(status)) {
		jobStatus = REMOVED;
	}

	jobAd->Assign(ATTR_STARTER_EXIT_STATUS, status);
	jobAd->Assign(ATTR_JOB_STATUS, jobStatus);

	if (s_claim) {
		bool badputFromDraining = s_claim->getBadputCausedByDraining();
		jobAd->Assign(ATTR_BADPUT_CAUSED_BY_DRAINING, badputFromDraining);
		bool badputFromPreemption = s_claim->getBadputCausedByPreemption();
		jobAd->Assign(ATTR_BADPUT_CAUSED_BY_PREEMPTION, badputFromPreemption);
	}
	AppendHistory(jobAd);
	WritePerJobHistoryFile(jobAd, true /* use gjid for filename*/);

	if (jobAdNeedsFree) {
		delete jobAd;
	}

		// Make sure our time isn't going to go off.
	cancelKillTimer();

		// Just for good measure, try to kill what's left of our whole
		// pid family.
	if (daemonCore->Kill_Family(s_pid) == FALSE) {
		dprintf(D_ALWAYS,
		        "error killing process family of starter with pid %u\n",
		        s_pid);
	}

		// Now, delete any files lying around.
	ASSERT( executeDir() );
	if ( encryptedExecuteDir() ) {
		// Remove $EXECUTE/encryptedX/dir_pid/*
		cleanup_execute_dir( s_pid, encryptedExecuteDir(), true );
		s_encrypted_execute_dir = "";
	} else {
		// Remove $EXECUTE/dir_pid/*
		cleanup_execute_dir( s_pid, executeDir() );
	}

#if defined(LINUX)
	if( param_boolean( "GLEXEC_STARTER", false ) ) {
		cleanupAfterGlexec();
	}
#endif
}
/*! handle a log Entry: work with a job queue collection.
 *  (not with DBMS directry)
 */
QuillErrCode
JobQueueDBManager::processLogEntry(int op_type, JobQueueCollection* jobQueue)
{
	char *key, *mytype, *targettype, *name, *value;
	key = mytype = targettype = name = value = NULL;
	QuillErrCode st = QUILL_SUCCESS;

	int job_id_type;
	char cid[512];
	char pid[512];

		// REMEMBER:
		//	each get*ClassAdBody() funtion allocates the memory of 
		// 	parameters. Therefore, they all must be deallocated here,
		// and they are at the end of the routine
	switch(op_type) {
	case CondorLogOp_NewClassAd: {
		if (caLogParser->getNewClassAdBody(key, mytype, targettype) == QUILL_FAILURE)
			{
				st = QUILL_FAILURE;
				break;
			}
		job_id_type = getProcClusterIds(key, cid, pid);
		ClassAd* ad = new ClassAd();
		SetMyTypeName(*ad, "Job");
		SetTargetTypeName(*ad, "Machine");

		switch(job_id_type) {
		case IS_CLUSTER_ID:
			jobQueue->insertClusterAd(cid, ad);
			break;

		case IS_PROC_ID:
			jobQueue->insertProcAd(cid, pid, ad);
			break;

		default:
			dprintf(D_ALWAYS, "[QUILL++] New ClassAd --- ERROR\n");
			st = QUILL_FAILURE; 
			break;
		}

		break;
	}
	case CondorLogOp_DestroyClassAd: {
		if (caLogParser->getDestroyClassAdBody(key) == QUILL_FAILURE) {
			st = QUILL_FAILURE; 
			break;		
		}

		job_id_type = getProcClusterIds(key, cid, pid);

		switch(job_id_type) {
		case IS_CLUSTER_ID:
			jobQueue->removeClusterAd(cid);
			break;

		case IS_PROC_ID: {
			ClassAd *clusterad = jobQueue->find(cid);
			ClassAd *procad = jobQueue->find(cid,pid);
			if(!clusterad || !procad) {
			    dprintf(D_ALWAYS, 
						"[QUILL++] Destroy ClassAd --- Cannot find clusterad "
						"or procad in memory job queue");
				st = QUILL_FAILURE; 
				break;
			}

			jobQueue->removeProcAd(cid, pid);
			
			break;
		}
		default:
			dprintf(D_ALWAYS, "[QUILL++] Destroy ClassAd --- ERROR\n");
			st = QUILL_FAILURE; 
			break;
		}

		break;
	}
	case CondorLogOp_SetAttribute: {	
		if (caLogParser->getSetAttributeBody(key, name, value) == QUILL_FAILURE) {
			st = QUILL_FAILURE; 
			break;
		}
						
		job_id_type = getProcClusterIds(key, cid, pid);

		char tmp[512];

		snprintf(tmp, 512, "%s = %s", name, value);

		switch (job_id_type) {
		case IS_CLUSTER_ID: {
			ClassAd* ad = jobQueue->findClusterAd(cid);
			if (ad != NULL) {
				ad->Insert(tmp);
			}
			else {
				dprintf(D_ALWAYS, "[QUILL++] ERROR: There is no such Cluster Ad[%s]\n", cid);
			}
			break;
		}
		case IS_PROC_ID: {
			ClassAd* ad = jobQueue->findProcAd(cid, pid);
			if (ad != NULL) {
				ad->Insert(tmp);
			}
			else {
				dprintf(D_ALWAYS, "[QUILL++] ERROR: There is no such Proc Ad[%s.%s]\n", cid, pid);
			}
			break;
		}
		default:
			dprintf(D_ALWAYS, "[QUILL++] Set Attribute --- ERROR\n");
			st = QUILL_FAILURE; 
			break;
		}
		break;
	}
	case CondorLogOp_DeleteAttribute: {
		if (caLogParser->getDeleteAttributeBody(key, name) == QUILL_FAILURE) {
			st = QUILL_FAILURE; 
			break;
		}

		job_id_type = getProcClusterIds(key, cid, pid);

		switch(job_id_type) {
		case IS_CLUSTER_ID: {
			ClassAd* ad = jobQueue->findClusterAd(cid);
			ad->Delete(name);
			break;
		}
		case IS_PROC_ID: {
			ClassAd* ad = jobQueue->findProcAd(cid, pid);
			ad->Delete(name);
			break;
		}
		default:
			dprintf(D_ALWAYS, "[QUILL++] Delete Attribute --- ERROR\n");
			st = QUILL_FAILURE; 
		}
		break;
	}
	case CondorLogOp_BeginTransaction:
		st = processBeginTransaction(true);
		break;
	case CondorLogOp_EndTransaction:
		st = processEndTransaction(true);
		break;
			// skip the log historical sequence number command
	case CondorLogOp_LogHistoricalSequenceNumber:
		break;
	default:
		printf("[QUILL++] Unsupported Job Queue Command\n");
		st = QUILL_FAILURE; 
		break;
	}

		// pointers are release
	if (key != NULL) free(key);
	if (mytype != NULL) free(mytype);
	if (targettype != NULL) free(targettype);
	if (name != NULL) free(name);
	if (value != NULL) free(value);
	return st;
}
ClassAd *CollectorEngine::
collect (int command,ClassAd *clientAd,const condor_sockaddr& from,int &insert,Sock *sock)
{
	ClassAd		*retVal;
	ClassAd		*pvtAd;
	int		insPvt;
	AdNameHashKey		hk;
	HashString	hashString;
	static int repeatStartdAds = -1;		// for debugging
	ClassAd		*clientAdToRepeat = NULL;
	_condor_auto_accum_runtime<collector_runtime_probe> rt(CollectorEngine_rucc_runtime);
	double rt_last = rt.begin;

	if (repeatStartdAds == -1) {
		repeatStartdAds = param_integer("COLLECTOR_REPEAT_STARTD_ADS",0);
	}

	if( !ValidateClassAd(command,clientAd,sock) ) {
		return NULL;
	}

	CollectorEngine_rucc_validateAd_runtime.Add(rt.tick(rt_last));

	// mux on command
	switch (command)
	{
	  case UPDATE_STARTD_AD:
	  case UPDATE_STARTD_AD_WITH_ACK:
		if ( repeatStartdAds > 0 ) {
			clientAdToRepeat = new ClassAd(*clientAd);
		}
		if (!makeStartdAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		hashString.Build( hk );

		CollectorEngine_rucc_makeHashKey_runtime.Add(rt.tick(rt_last));

		retVal=updateClassAd (StartdAds, "StartdAd     ", "Start",
							  clientAd, hk, hashString, insert, from );

		if (last_updateClassAd_was_insert) { CollectorEngine_rucc_insertAd_runtime.Add(rt.tick(rt_last));
		} else { CollectorEngine_rucc_updateAd_runtime.Add(rt.tick(rt_last)); }

		// if we want to store private ads
		if (!sock)
		{
			dprintf (D_ALWAYS, "Want private ads, but no socket given!\n");
			break;
		}
		else
		{
			if (!(pvtAd = new ClassAd))
			{
				EXCEPT ("Memory error!");
			}
			if( !getClassAd(sock, *pvtAd) )
			{
				dprintf(D_FULLDEBUG,"\t(Could not get startd's private ad)\n");
				delete pvtAd;
				break;
			}

				// Fix up some stuff in the private ad that we depend on.
				// We started doing this in 7.2.0, so once we no longer
				// care about compatibility with stuff from before then,
				// the startd could stop bothering to send these attributes.

				// Queries of private ads depend on the following:
			SetMyTypeName( *pvtAd, STARTD_ADTYPE );

				// Negotiator matches up private ad with public ad by
				// using the following.
			if( retVal ) {
				CopyAttribute( ATTR_MY_ADDRESS, *pvtAd, *retVal );
				CopyAttribute( ATTR_NAME, *pvtAd, *retVal );
			}

			CollectorEngine_rucc_getPvtAd_runtime.Add(rt.tick(rt_last));

			// insert the private ad into its hashtable --- use the same
			// hash key as the public ad
			(void) updateClassAd (StartdPrivateAds, "StartdPvtAd  ",
								  "StartdPvt", pvtAd, hk, hashString, insPvt,
								  from );
			if (last_updateClassAd_was_insert) { CollectorEngine_rucc_insertPvtAd_runtime.Add(rt.tick(rt_last));
			} else { CollectorEngine_rucc_updatePvtAd_runtime.Add(rt.tick(rt_last)); }
		}

		// create fake duplicates of this ad, each with a different name, if
		// we are told to do so.  this feature exists for developer
		// scalability testing.
		if ( repeatStartdAds > 0 && clientAdToRepeat ) {
			ClassAd *fakeAd;
			int n;
			char newname[150],oldname[130];
			oldname[0] = '\0';
			clientAdToRepeat->LookupString("Name",oldname,sizeof(oldname));
			for (n=0;n<repeatStartdAds;n++) {
				fakeAd = new ClassAd(*clientAdToRepeat);
				snprintf(newname,sizeof(newname),
						 "Name=\"fake%d-%s\"",n,oldname);
				fakeAd->Insert(newname);
				makeStartdAdHashKey (hk, fakeAd);
				hashString.Build( hk );
				if (! updateClassAd (StartdAds, "StartdAd     ", "Start",
							  fakeAd, hk, hashString, insert, from ) )
				{
					// don't leak memory if there is some failure
					delete fakeAd;
				}
			}
			delete clientAdToRepeat;
			clientAdToRepeat = NULL;
			CollectorEngine_rucc_repeatAd_runtime.Add(rt.tick(rt_last));
		}
		break;

	  case MERGE_STARTD_AD:
		if (!makeStartdAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		hashString.Build( hk );
		retVal=mergeClassAd (StartdAds, "StartdAd     ", "Start",
							  clientAd, hk, hashString, insert, from );
		break;

	  case UPDATE_SCHEDD_AD:
		if (!makeScheddAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		hashString.Build( hk );
		retVal=updateClassAd (ScheddAds, "ScheddAd     ", "Schedd",
							  clientAd, hk, hashString, insert, from );
		break;

	  case UPDATE_SUBMITTOR_AD:
		// use the same hashkey function as a schedd ad
		if (!makeScheddAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		// since submittor ads always follow a schedd ad, and a master check is
		// performed for schedd ads, we don't need a master check in here
		hashString.Build( hk );
		retVal=updateClassAd (SubmittorAds, "SubmittorAd  ", "Submittor",
							  clientAd, hk, hashString, insert, from );
		break;

	  case UPDATE_LICENSE_AD:
		// use the same hashkey function as a schedd ad
		if (!makeLicenseAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		// since submittor ads always follow a schedd ad, and a master check is
		// performed for schedd ads, we don't need a master check in here
		hashString.Build( hk );
		retVal=updateClassAd (LicenseAds, "LicenseAd  ", "License",
							  clientAd, hk, hashString, insert, from );
		break;

	  case UPDATE_MASTER_AD:
		if (!makeMasterAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		hashString.Build( hk );
		retVal=updateClassAd (MasterAds, "MasterAd     ", "Master",
							  clientAd, hk, hashString, insert, from );
		break;

	  case UPDATE_CKPT_SRVR_AD:
		if (!makeCkptSrvrAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		hashString.Build( hk );
		retVal=updateClassAd (CkptServerAds, "CkptSrvrAd   ", "CkptSrvr",
							  clientAd, hk, hashString, insert, from );
		break;

	  case UPDATE_COLLECTOR_AD:
		if (!makeCollectorAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		hashString.Build( hk );
		retVal=updateClassAd (CollectorAds, "CollectorAd  ", "Collector",
							  clientAd, hk, hashString, insert, from );
		break;

	  case UPDATE_STORAGE_AD:
		if (!makeStorageAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		hashString.Build( hk );
		retVal=updateClassAd (StorageAds, "StorageAd  ", "Storage",
							  clientAd, hk, hashString, insert, from );
		break;

	  case UPDATE_ACCOUNTING_AD:
		if (!makeAccountingAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		hashString.Build( hk );
		retVal=updateClassAd (AccountingAds, "AccountingAd  ", "Accouting",
							  clientAd, hk, hashString, insert, from );
		break;

	  case UPDATE_NEGOTIATOR_AD:
		if (!makeNegotiatorAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		hashString.Build( hk );
		if (m_allowOnlyOneNegotiator) {
			// first, purge all the existing negotiator ads, since we
			// want to enforce that *ONLY* 1 negotiator is in the
			// collector any given time.
			purgeHashTable( NegotiatorAds );
		}
		retVal=updateClassAd (NegotiatorAds, "NegotiatorAd  ", "Negotiator",
							  clientAd, hk, hashString, insert, from );
		break;

	  case UPDATE_HAD_AD:
		if (!makeHadAdHashKey (hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		hashString.Build( hk );
		retVal=updateClassAd (HadAds, "HadAd  ", "HAD",
							  clientAd, hk, hashString, insert, from );
		break;

	  case UPDATE_GRID_AD:
		if (!makeGridAdHashKey(hk, clientAd))
		{
			dprintf (D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			insert = -3;
			retVal = 0;
			break;
		}
		hashString.Build( hk );
		retVal=updateClassAd (GridAds, "GridAd  ", "Grid",
							  clientAd, hk, hashString, insert, from );
          break;

	  case UPDATE_AD_GENERIC:
	  {
		  const char *type_str = GetMyTypeName(*clientAd);
		  if (type_str == NULL) {
			  dprintf(D_ALWAYS, "collect: UPDATE_AD_GENERIC: ad has no type\n");
			  insert = -3;
			  retVal = 0;
			  break;
		  }
		  MyString type(type_str);
		  CollectorHashTable *cht = findOrCreateTable(type);
		  if (cht == NULL) {
			  dprintf(D_ALWAYS, "collect: findOrCreateTable failed\n");
			  insert = -3;
			  retVal = 0;
			  break;
		  }
		  if (!makeGenericAdHashKey (hk, clientAd))
		  {
			  dprintf(D_ALWAYS, "Could not make hashkey --- ignoring ad\n");
			  insert = -3;
			  retVal = 0;
			  break;
		  }
		  hashString.Build(hk);
		  retVal = updateClassAd(*cht, type_str, type_str, clientAd,
					 hk, hashString, insert, from);
		  break;
	  }

	  case QUERY_STARTD_ADS:
	  case QUERY_SCHEDD_ADS:
	  case QUERY_MASTER_ADS:
	  case QUERY_SUBMITTOR_ADS:
	  case QUERY_CKPT_SRVR_ADS:
	  case QUERY_STARTD_PVT_ADS:
	  case QUERY_COLLECTOR_ADS:
  	  case QUERY_NEGOTIATOR_ADS:
  	  case QUERY_HAD_ADS:
	  case QUERY_GENERIC_ADS:
	  case INVALIDATE_STARTD_ADS:
	  case INVALIDATE_SCHEDD_ADS:
	  case INVALIDATE_MASTER_ADS:
	  case INVALIDATE_CKPT_SRVR_ADS:
	  case INVALIDATE_SUBMITTOR_ADS:
	  case INVALIDATE_COLLECTOR_ADS:
	  case INVALIDATE_NEGOTIATOR_ADS:
	  case INVALIDATE_HAD_ADS:
	  case INVALIDATE_ADS_GENERIC:
		// these are not implemented in the engine, but we allow another
		// daemon to detect that these commands have been given
	    insert = -2;
		retVal = 0;
	    break;

	  default:
		dprintf (D_ALWAYS, "Received illegal command: %d\n", command);
		insert = -1;
		retVal = 0;
	}

	if (command != UPDATE_STARTD_AD && command != UPDATE_STARTD_AD_WITH_ACK) {
		CollectorEngine_rucc_other_runtime.Add(rt.tick(rt_last));
	}


	// return the updated ad
	return retVal;
}