od_query_create_with_node.c [plain text]
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "../libmicro.h"
#include <CoreFoundation/CFArray.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFDictionary.h>
#include <OpenDirectory/OpenDirectory.h>
#include <DirectoryService/DirectoryService.h>
#if DEBUG
# define debug(fmt, args...) (void) fprintf(stderr, fmt , ##args)
#else
# define debug(fmt, args...)
#endif
#define LOCAL_U_PREFIX CFSTR("local_test_")
#define OD_U_PREFIX CFSTR("od_test_")
#define LOCAL_G_PREFIX CFSTR("local_test_group_")
#define OD_G_PREFIX CFSTR("od_test_group_")
#define LOCAL_H_PREFIX CFSTR("local_test_host_")
#define OD_H_PREFIX CFSTR("od_test_host_")
typedef struct {
ODNodeRef node;
} tsd_t;
enum {rectype_users=0, rectype_groups, rectype_hosts};
CFStringRef rectype_dict[] = { CFSTR(kDSStdRecordTypeUsers),
CFSTR(kDSStdRecordTypeGroups),
CFSTR(kDSStdRecordTypeHosts) };
static int optRecords = 100; static int optCachehit = 100; static bool optNodeLocal = 1; static int optType = rectype_users; static const char *nodename = "/LDAPv3/127.0.0.1";
static CFStringRef *key;
int
ds_rec_type(char *name)
{
if (strcasecmp("u", name) == 0) {
return (rectype_users);
} else if (strcasecmp("g", name) == 0) {
return (rectype_groups);
} else if (strcasecmp("h", name) == 0) {
return (rectype_hosts);
}
return (-1);
}
int
benchmark_init()
{
debug("benchmark_init");
(void) sprintf(lm_optstr, "c:n:r:t:");
lm_tsdsize = sizeof (tsd_t);
lm_defB = 1000;
(void) sprintf(lm_usage,
"\n ------- od_query_create_with_node specific options (default: *)\n"
" [-c hitrate%% (100%%*)]\n"
" [-r total number of records (100*)]\n"
" [-n nodename] node name to use for test\n"
" [-t record type: 'u'sers, 'g'roups, 'h'osts]\n"
" use -B option to specify total number of record lookups to issue"
"\n" );
return (0);
}
int
benchmark_optswitch(int opt, char *optarg)
{
debug("benchmark_optswitch");
switch (opt) {
case 'c': optCachehit = atoi(optarg);
debug("optCachehit = %d\n", optCachehit);
if (optCachehit > 100 || optCachehit < 0) {
printf("cache hit rate should be in between 0%% and 100%%");
return (-1);
}
break;
case 'r': optRecords = atoi(optarg);
debug("optRecords = %d\n", optRecords);
break;
case 'n': nodename = optarg;
break;
case 't': optType = ds_rec_type(optarg);
debug("optType = %d\n", optType);
if (optType == -1) {
printf("wrong -t record type option\n");
return (-1);
}
break;
default:
return (-1);
}
return (0);
}
int
benchmark_initrun()
{
int i;
CFStringRef prefix;
debug("benchmark_initrun\n");
if (optCachehit < 100) {
optRecords = (int) ((float) optRecords * ((float) optCachehit / 100));
debug("# of records adjusted to %d for cache hit rate %d%%\n", optRecords, optCachehit);
}
if (lm_optB < optRecords) {
lm_optB = optRecords;
debug("Adjusting batch size to %d to match the lookups required in benchmark run\n", lm_optB);
}
switch (optType) {
case rectype_users:
prefix = (optNodeLocal) ? LOCAL_U_PREFIX : OD_U_PREFIX;
break;
case rectype_groups:
prefix = (optNodeLocal) ? LOCAL_G_PREFIX : OD_G_PREFIX;
break;
case rectype_hosts:
prefix = (optNodeLocal) ? LOCAL_H_PREFIX : OD_H_PREFIX;
break;
}
key = malloc(sizeof(CFStringRef) * optRecords);
switch (optType) {
case rectype_users: case rectype_groups: case rectype_hosts: for (i = 0; i < optRecords; i++) {
key[i] = CFStringCreateWithFormat( kCFAllocatorDefault,
NULL,
CFSTR("%@%d"),
prefix,
i+1);
}
break;
}
return (0);
}
int
benchmark_initworker(void *tsd)
{
CFErrorRef error;
tsd_t *ts = (tsd_t *)tsd;
debug("benchmark_initworker: %s", (optNodeLocal) ? "local" : "network");
if (optNodeLocal) {
ts->node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODNodeTypeLocalNodes, &error);
}
else {
CFStringRef nodenameStr = CFStringCreateWithCString(kCFAllocatorDefault, nodename, kCFStringEncodingUTF8);
ts->node = ODNodeCreateWithName(NULL, kODSessionDefault, nodenameStr, &error);
CFRelease(nodenameStr);
}
if (!ts->node) {
debug("error calling ODNodeCreateWithNodeType\n");
exit(1);
}
CFRetain (ts->node);
debug("benchmark_initworker: ODNodeRef = 0x%lx\n", ts->node);
return (0);
}
int
benchmark(void *tsd, result_t *res)
{
tsd_t *ts = (tsd_t *)tsd;
int i;
ODNodeRef node;
CFErrorRef error;
CFArrayRef results;
ODQueryRef query;
res->re_errors = 0;
node = ts->node;
debug("in to benchmark - optB = %i, node = 0x%lx \n", lm_optB, node);
for (i = 0; i < lm_optB; i++) {
debug("loop %d: querying\n", i);
query = ODQueryCreateWithNode(NULL,
node, rectype_dict[optType], CFSTR(kDSNAttrRecordName), kODMatchInsensitiveEqualTo, key[i % optRecords], NULL, 1, &error);
if (query) {
results = ODQueryCopyResults(query, FALSE, &error);
CFRelease(query);
if (results) {
#if DEBUG
int c;
c = CFArrayGetCount(results);
if (c > 0) {
debug("Successful run: %d results, ", c);
}
else {
debug("no result for ");
}
CFShow (key[i % optRecords]);
debug("\n");
#endif
CFRelease(results);
}
else {
debug("loop %d: ODQueryCopyResults returned empty result for ", i);
res->re_errors++;
CFShow (key[i % optRecords]);
debug("\n");
}
} else {
res->re_errors++;
}
}
res->re_count = i;
return (0);
}
int
benchmark_finiworker(void *tsd)
{
tsd_t *ts = (tsd_t *)tsd;
debug("benchmark_result: deallocating structures\n");
if (ts->node)
CFRelease (ts->node);
ts->node = NULL;
return (0);
}
int
benchmark_finirun()
{
int i;
for (i = 0; i < optRecords; i++){
CFRelease(key[i]);
}
free(key);
return (0);
}
char *
benchmark_result()
{
static char result = '\0';
debug("\n\n# of records adjusted to %d for cache hit rate %d%%\n", optRecords, optCachehit);
debug("benchmark_result\n");
return (&result);
}