<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2011, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_state.h"
#include "enum_utils.h"
#include "condor_attributes.h"
#include "MyString.h"
#include "stdio.h"
#include "HashTable.h"
#include "totals.h"
#include "string_list.h"

#ifndef WIN32
#endif


TrackTotals::
TrackTotals (ppOption m) : allTotals(16, MyStringHash)
{
	ppo = m;
	malformed = 0;
	topLevelTotal = ClassTotal::makeTotalObject(ppo);
}

TrackTotals::
~TrackTotals ()
{
	ClassTotal *ct;

	allTotals.startIterations();
	while (allTotals.iterate(ct))
		delete ct;
	delete topLevelTotal;
}

int TrackTotals::
update (ClassAd *ad, int options, const char * _key /*=NULL*/)
{
	ClassTotal *ct;
	MyString	key(_key);
	int		   	rval;

	if ( key.empty() && ! ClassTotal::makeKey(key, ad, ppo))
	{
		malformed++;
		return 0;
	}

	if (allTotals.lookup (key, ct) < 0)
	{
		ct = ClassTotal::makeTotalObject (ppo);
		if (!ct) return 0;
		if (allTotals.insert (key, ct) < 0)
		{
			delete ct;
			return 0;
		}
	}

	rval = ct->update(ad, options);
	topLevelTotal->update(ad, options);

	if (rval == 0) malformed++;

	return rval;
}

bool TrackTotals::haveTotals()
{
	// display totals only for meaningful modes
	switch (ppo)
	{
    	case PP_STARTD_NORMAL:
    	case PP_STARTD_SERVER:
    	case PP_STARTD_RUN:
		case PP_STARTD_STATE:
    	case PP_STARTD_COD:

#ifdef HAVE_EXT_POSTGRESQL
    	case PP_QUILL_NORMAL:
#endif /* HAVE_EXT_POSTGRESQL */

    	case PP_SCHEDD_NORMAL:
    	case PP_SUBMITTER_NORMAL:
    	case PP_CKPT_SRVR_NORMAL:
			break;

		default:
			return false;
	}
	return true;
}


void TrackTotals::
displayTotals (FILE *file, int keyLength)
{
	ClassTotal *ct=0;
	MyString	key;
	int k;
	bool auto_key_length = keyLength < 0;
	if (auto_key_length) { keyLength = 5; } // must be at least 5 for "Total"

	// display totals only for meaningful modes
	if ( ! haveTotals()) return;

		
	// sort the keys (insertion sort) so we display totals in sorted order
	const char **keys = new const char* [allTotals.getNumElements()];
	ASSERT(keys);
	allTotals.startIterations();
	for (k = 0; k < allTotals.getNumElements(); k++) // for each key
	{
		allTotals.iterate(key, ct);
		// find the position where we want to insert the key
		int pos;
		for (pos = 0; pos < k && strcmp(keys[pos], key.Value()) < 0; pos++) { }
		if (pos < k) {
			// if we are not inserting at the end of the array, then
			// we must shift the elements to the right to make room;
			// we use memmove() because it handles overlapping buffers
			// correctly (and efficiently)
			memmove(keys+pos+1, keys+pos, (k-pos)*sizeof(char *));
		}
		// insert the key in the right position in the list
		keys[pos] = strdup(key.Value());
		if (auto_key_length) {
			keyLength = MAX(keyLength, key.Length());
		}
	}

	// display the lead of the header
	fprintf (file, "%*.*s", keyLength, keyLength, "");
	topLevelTotal->displayHeader(file);
	fprintf (file, "\n");

	// now that our keys are sorted, display the totals in sort order
	bool had_tot_keys = false;
	for (k = 0; k < allTotals.getNumElements(); k++)
	{
		fprintf (file, "%*.*s", keyLength, keyLength, keys[k]);
		allTotals.lookup(MyString(keys[k]), ct);
		free((void *)const_cast<char*>(keys[k]));
		ct->displayInfo(file);
		had_tot_keys = true;
	}
	delete [] keys;
	if( allTotals.getNumElements() > 1 ) {
		if (had_tot_keys) fprintf(file, "\n");
		fprintf (file, "%*.*s", keyLength, keyLength, "Total");
		topLevelTotal->displayInfo(file,1);
	}

	if (malformed > 0)
	{
		fprintf(file, "\n%*.*s(Omitted %d malformed ads in computed attribute "
					"totals)\n\n", keyLength, keyLength, "", malformed);
	}
}



StartdNormalTotal::
StartdNormalTotal()
{
	ppo = PP_STARTD_NORMAL;
	machines = 0;
	owner = 0;<commit_msg>(#6321)  Add the redundant totals line back in; some users might (and our tests do) depend on it, because there's no other way to get those numbers yet.<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2011, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_state.h"
#include "enum_utils.h"
#include "condor_attributes.h"
#include "MyString.h"
#include "stdio.h"
#include "HashTable.h"
#include "totals.h"
#include "string_list.h"

#ifndef WIN32
#endif


TrackTotals::
TrackTotals (ppOption m) : allTotals(16, MyStringHash)
{
	ppo = m;
	malformed = 0;
	topLevelTotal = ClassTotal::makeTotalObject(ppo);
}

TrackTotals::
~TrackTotals ()
{
	ClassTotal *ct;

	allTotals.startIterations();
	while (allTotals.iterate(ct))
		delete ct;
	delete topLevelTotal;
}

int TrackTotals::
update (ClassAd *ad, int options, const char * _key /*=NULL*/)
{
	ClassTotal *ct;
	MyString	key(_key);
	int		   	rval;

	if ( key.empty() && ! ClassTotal::makeKey(key, ad, ppo))
	{
		malformed++;
		return 0;
	}

	if (allTotals.lookup (key, ct) < 0)
	{
		ct = ClassTotal::makeTotalObject (ppo);
		if (!ct) return 0;
		if (allTotals.insert (key, ct) < 0)
		{
			delete ct;
			return 0;
		}
	}

	rval = ct->update(ad, options);
	topLevelTotal->update(ad, options);

	if (rval == 0) malformed++;

	return rval;
}

bool TrackTotals::haveTotals()
{
	// display totals only for meaningful modes
	switch (ppo)
	{
    	case PP_STARTD_NORMAL:
    	case PP_STARTD_SERVER:
    	case PP_STARTD_RUN:
		case PP_STARTD_STATE:
    	case PP_STARTD_COD:

#ifdef HAVE_EXT_POSTGRESQL
    	case PP_QUILL_NORMAL:
#endif /* HAVE_EXT_POSTGRESQL */

    	case PP_SCHEDD_NORMAL:
    	case PP_SUBMITTER_NORMAL:
    	case PP_CKPT_SRVR_NORMAL:
			break;

		default:
			return false;
	}
	return true;
}


void TrackTotals::
displayTotals (FILE *file, int keyLength)
{
	ClassTotal *ct=0;
	MyString	key;
	int k;
	bool auto_key_length = keyLength < 0;
	if (auto_key_length) { keyLength = 5; } // must be at least 5 for "Total"

	// display totals only for meaningful modes
	if ( ! haveTotals()) return;

		
	// sort the keys (insertion sort) so we display totals in sorted order
	const char **keys = new const char* [allTotals.getNumElements()];
	ASSERT(keys);
	allTotals.startIterations();
	for (k = 0; k < allTotals.getNumElements(); k++) // for each key
	{
		allTotals.iterate(key, ct);
		// find the position where we want to insert the key
		int pos;
		for (pos = 0; pos < k && strcmp(keys[pos], key.Value()) < 0; pos++) { }
		if (pos < k) {
			// if we are not inserting at the end of the array, then
			// we must shift the elements to the right to make room;
			// we use memmove() because it handles overlapping buffers
			// correctly (and efficiently)
			memmove(keys+pos+1, keys+pos, (k-pos)*sizeof(char *));
		}
		// insert the key in the right position in the list
		keys[pos] = strdup(key.Value());
		if (auto_key_length) {
			keyLength = MAX(keyLength, key.Length());
		}
	}

	// display the lead of the header
	fprintf (file, "%*.*s", keyLength, keyLength, "");
	topLevelTotal->displayHeader(file);
	fprintf (file, "\n");

	// now that our keys are sorted, display the totals in sort order
	bool had_tot_keys = false;
	for (k = 0; k < allTotals.getNumElements(); k++)
	{
		fprintf (file, "%*.*s", keyLength, keyLength, keys[k]);
		allTotals.lookup(MyString(keys[k]), ct);
		free((void *)const_cast<char*>(keys[k]));
		ct->displayInfo(file);
		had_tot_keys = true;
	}
	delete [] keys;
	if (had_tot_keys) fprintf(file, "\n");
	fprintf (file, "%*.*s", keyLength, keyLength, "Total");
	topLevelTotal->displayInfo(file,1);

	if (malformed > 0)
	{
		fprintf(file, "\n%*.*s(Omitted %d malformed ads in computed attribute "
					"totals)\n\n", keyLength, keyLength, "", malformed);
	}
}



StartdNormalTotal::
StartdNormalTotal()
{
	ppo = PP_STARTD_NORMAL;
	machines = 0;
	owner = 0;
{'fraction_non_alphanumeric': 0.1560197910940077, 'fraction_numerical': 0.008466190214403518, 'mean_word_length': 3.9569482288828337, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4122741', 'n_tokens_mistral': 3389, 'n_tokens_neox': 3119, 'n_words': 953}