/** * Main daemon routine */ int main( int argc, char **argv ) { int c, i, option_index = 0; char *bin = basename( argv[0] ); int rc; char err_msg[4096]; robinhood_config_t rh_config; int chgd = 0; char badcfg[RBH_PATH_MAX]; char tag_name[256] = ""; start_time = time( NULL ); zero_options( &options ); /* parse command line options */ while ( ( c = getopt_long( argc, argv, SHORT_OPT_STRING, option_tab, &option_index ) ) != -1 ) { switch ( c ) { case 's': options.partial_scan = TRUE; rh_strncpy(options.partial_scan_path, optarg, RBH_PATH_MAX); /* clean final slash */ if (FINAL_SLASH(options.partial_scan_path)) REMOVE_FINAL_SLASH(options.partial_scan_path); break; case 'd': if (parse_diff_mask(optarg, &options.diff_mask, err_msg)) { fprintf(stderr, "Invalid argument for --diff: %s\n", err_msg); exit( 1 ); } break; case 'a': if (optarg) { if (!strcasecmp(optarg,"fs")) options.diff_arg.apply = APPLY_FS; else if (!strcasecmp(optarg,"db")) options.diff_arg.apply = APPLY_DB; else { fprintf(stderr, "Invalid argument for --apply: '%s' (fs or db expected)\n", optarg); exit( 1 ); } } else options.diff_arg.apply = APPLY_DB; break; case 'D': options.flags |= FLAG_DRY_RUN; break; case 'f': rh_strncpy(options.config_file, optarg, MAX_OPT_LEN); break; #ifdef _HSM_LITE case 'b': options.diff_arg.recov_from_backend = 1; break; #endif #ifdef _HAVE_FID /* only for lustre 2.x */ case 'o': rh_strncpy(options.output_dir, optarg, MAX_OPT_LEN); break; #endif case 'l': options.force_log_level = TRUE; options.log_level = str2debuglevel( optarg ); if ( options.log_level == -1 ) { fprintf( stderr, "Unsupported log level '%s'. CRIT, MAJOR, EVENT, VERB, DEBUG or FULL expected.\n", optarg ); exit( 1 ); } break; case 'h': display_help( bin ); exit( 0 ); break; case 'V': display_version( bin ); exit( 0 ); break; case ':': case '?': default: fprintf(stderr,"Run '%s --help' for more details.\n", bin); exit( 1 ); break; } } /* check there is no extra arguments */ if ( optind != argc ) { fprintf( stderr, "Error: unexpected argument on command line: %s\n", argv[optind] ); exit( 1 ); } /* Initialize global tools */ #ifdef _LUSTRE if ( ( rc = Lustre_Init( ) ) ) { fprintf( stderr, "Error %d initializing liblustreapi\n", rc ); exit( 1 ); } #endif /* Initilize uidgid cache */ if ( InitUidGid_Cache( ) ) { fprintf( stderr, "Error initializing uid/gid cache\n" ); exit( 1 ); } /* get default config file, if not specified */ if (SearchConfig(options.config_file, options.config_file, &chgd, badcfg, MAX_OPT_LEN) != 0) { fprintf(stderr, "No config file (or too many) found matching %s\n", badcfg); exit(2); } else if (chgd) { fprintf(stderr, "Using config file '%s'.\n", options.config_file ); } if ( ReadRobinhoodConfig( MODULE_MASK_FS_SCAN | MODULE_MASK_ENTRY_PROCESSOR, options.config_file, err_msg, &rh_config, FALSE ) ) { fprintf( stderr, "Error reading configuration file '%s': %s\n", options.config_file, err_msg ); exit( 1 ); } process_config_file = options.config_file; /* set global configuration */ global_config = rh_config.global_config; /* set policies info */ policies = rh_config.policies; if (options.force_log_level) rh_config.log_config.debug_level = options.log_level; else rh_config.log_config.debug_level = LVL_CRIT; /* no event message */ /* Set logging to stderr */ strcpy( rh_config.log_config.log_file, "stderr" ); strcpy( rh_config.log_config.report_file, "stderr" ); strcpy( rh_config.log_config.alert_file, "stderr" ); /* Initialize logging */ rc = InitializeLogs( bin, &rh_config.log_config ); if ( rc ) { fprintf( stderr, "Error opening log files: rc=%d, errno=%d: %s\n", rc, errno, strerror( errno ) ); exit( rc ); } /* Initialize filesystem access */ rc = InitFS(); if (rc) exit(rc); #ifdef _HSM_LITE rc = Backend_Start( &rh_config.backend_config, options.flags ); if ( rc ) { DisplayLog( LVL_CRIT, DIFF_TAG, "Error initializing backend" ); exit( 1 ); } #endif /* Initialize list manager */ rc = ListMgr_Init( &rh_config.lmgr_config, FALSE ); if ( rc ) { DisplayLog( LVL_CRIT, DIFF_TAG, "Error %d initializing list manager", rc ); exit( rc ); } else DisplayLog( LVL_VERB, DIFF_TAG, "ListManager successfully initialized" ); if ( CheckLastFS( ) != 0 ) exit( 1 ); if (options.diff_mask) rh_config.entry_proc_config.diff_mask = options.diff_mask; else { /* parse "all" */ char tmpstr[] = "all"; if (parse_diff_mask(tmpstr, &rh_config.entry_proc_config.diff_mask, err_msg)) { DisplayLog(LVL_CRIT, DIFF_TAG, "unexpected error parsing diff mask: %s", err_msg); exit(1); } } #ifdef LUSTRE_DUMP_FILES if (options.diff_arg.apply == APPLY_FS && !(options.flags & FLAG_DRY_RUN)) { /* open the file to write LOV EA and FID remapping */ if (!EMPTY_STRING(options.output_dir)) { char fname[RBH_PATH_MAX]; if (mkdir(options.output_dir, 0700) && (errno != EEXIST)) { DisplayLog(LVL_CRIT, DIFF_TAG, "Failed to create directory %s: %s", options.output_dir, strerror(errno)); exit(1); } snprintf(fname, RBH_PATH_MAX-1, "%s/"LOVEA_FNAME, options.output_dir); options.diff_arg.lovea_file = fopen(fname, "w"); if (options.diff_arg.lovea_file == NULL) { DisplayLog(LVL_CRIT, DIFF_TAG, "Failed to open %s for writting: %s", fname, strerror(errno)); exit(1); } snprintf(fname, RBH_PATH_MAX-1, "%s/"FIDREMAP_FNAME, options.output_dir); options.diff_arg.fid_remap_file = fopen(fname, "w"); if (options.diff_arg.fid_remap_file == NULL) { DisplayLog(LVL_CRIT, DIFF_TAG, "Failed to open %s for writting: %s", fname, strerror(errno)); exit(1); } } } #endif /* if no DB apply action is specified, can't use md_update field for checking * removed entries. So, create a special tag for that. */ if ((options.diff_arg.apply != APPLY_DB) || (options.flags & FLAG_DRY_RUN)) { fprintf(stderr, "Preparing diff table...\n"); /* create a connexion to the DB. this is safe to use the global lmgr var * as statistics thread is not running */ if (!ensure_db_access()) exit(1); /* create a tag to clear entries after the scan */ /* There could be several diff running in parallel, * so set a suffix to avoid conflicts */ sprintf(tag_name, "DIFF_%u", (unsigned int) getpid()); options.diff_arg.db_tag = tag_name; /* add filter for partial scan */ if (options.partial_scan) { lmgr_filter_t filter; filter_value_t val; lmgr_simple_filter_init( &filter ); char tmp[RBH_PATH_MAX]; strcpy(tmp, options.partial_scan_path); strcat(tmp, "/*"); val.value.val_str = tmp; lmgr_simple_filter_add(&filter, ATTR_INDEX_fullpath, LIKE, val, 0); rc = ListMgr_CreateTag(&lmgr, tag_name, &filter, FALSE); lmgr_simple_filter_free(&filter); } else rc = ListMgr_CreateTag(&lmgr, tag_name, NULL, FALSE); if (rc) exit(rc); } /* Initialise Pipeline */ rc = EntryProcessor_Init(&rh_config.entry_proc_config, DIFF_PIPELINE, options.flags, &options.diff_arg); if ( rc ) { DisplayLog( LVL_CRIT, DIFF_TAG, "Error %d initializing EntryProcessor pipeline", rc ); goto clean_tag; } else DisplayLog( LVL_VERB, DIFF_TAG, "EntryProcessor successfully initialized" ); fprintf(stderr, "Starting scan\n"); /* print header to indicate the content of diff * #<diff cmd> * ---fs[=/subdir] * +++db */ for (i = 0; i < argc; i++) printf("%s%s", i==0?"# ":" ", argv[i]); printf("\n"); if (options.diff_arg.apply == APPLY_FS) { if (options.partial_scan) printf("---fs=%s\n",options.partial_scan_path); else printf("---fs\n"); printf("+++db\n"); } else { printf("---db\n"); if (options.partial_scan) printf("+++fs=%s\n",options.partial_scan_path); else printf("+++fs\n"); } /* Start FS scan */ if (options.partial_scan) rc = FSScan_Start(&rh_config.fs_scan_config, options.flags, options.partial_scan_path); else rc = FSScan_Start(&rh_config.fs_scan_config, options.flags, NULL); if ( rc ) { DisplayLog( LVL_CRIT, DIFF_TAG, "Error %d initializing FS Scan module", rc ); goto clean_tag; } else DisplayLog( LVL_VERB, DIFF_TAG, "FS Scan module successfully initialized" ); /* Flush logs now, to have a trace in the logs */ FlushLogs( ); /* both pipeline and scan are now running, can now trap events and display stats */ /* create signal handling thread */ rc = pthread_create( &sig_thr, NULL, signal_handler_thr, NULL ); if ( rc ) { DisplayLog( LVL_CRIT, DIFF_TAG, "Error starting signal handler thread: %s", strerror( errno ) ); goto clean_tag; } else DisplayLog( LVL_VERB, DIFF_TAG, "Signal handler thread started successfully" ); pthread_create(&stat_thread, NULL, stats_thr, NULL); /* wait for FS scan to end */ FSScan_Wait( ); DisplayLog( LVL_MAJOR, DIFF_TAG, "FS Scan finished" ); /* Pipeline must be flushed */ EntryProcessor_Terminate( TRUE ); #ifdef LUSTRE_DUMP_FILES /* flush the lovea file */ if (options.diff_arg.lovea_file) { fprintf(stderr, " > LOV EA information written to %s/"LOVEA_FNAME"\n", options.output_dir); fclose(options.diff_arg.lovea_file); } if (options.diff_arg.fid_remap_file) { fprintf(stderr, " > FID remapping written to %s/"FIDREMAP_FNAME"\n", options.output_dir); fclose(options.diff_arg.fid_remap_file); } #endif fprintf(stderr, "End of scan\n"); DisplayLog( LVL_MAJOR, DIFF_TAG, "All tasks done! Exiting." ); rc = 0; clean_tag: /* destroy the tag before exit */ if (options.diff_arg.db_tag != NULL && ensure_db_access()) { fprintf(stderr, "Cleaning diff table...\n"); ListMgr_DestroyTag(&lmgr, options.diff_arg.db_tag); } exit(rc); return rc; /* for compiler */ }
int main( int argc, char **argv ) { int i; pthread_t worker[NB_WORKER]; void *dummy; pthread_attr_t attr; robinhood_config_t config; char err_msg[2048]; srand( time( NULL ) + getpid( ) ); if ( argc < 2 ) { fprintf( stderr, "Usage : test_fs_scan <config_file>\n" ); exit( 1 ); } /* Initilize uidgid cache */ if ( InitUidGid_Cache( ) ) { fprintf( stderr, "Error initializing uid/gid cache\n" ); exit( 1 ); } /* only parse config for mandatory module */ if ( ReadRobinhoodConfig ( MODULE_MASK_ENTRY_PROCESSOR | MODULE_MASK_INFO_COLLECTOR, argv[1], err_msg, &config ) ) { fprintf( stderr, "Error reading configuration:\n%s\n", err_msg ); exit( 1 ); } /* set global configuration */ global_config = config.global_config; /* set policies */ purge_policy = config.purge_policy; InitializeLogs( "test_fs_scan", &config.log_config ); /* Initialise List Mgr */ if ( ListMgr_Init( &config.lmgr_config ) ) { printf( "List Mgr init error" ); return -1; } /* Initialise Pipeline */ if ( EntryProcessor_Init( &config.entry_proc_config ) ) { printf( "Pipeline init error" ); return -1; } /* Start info collectors */ if ( Start_Info_Collectors( &config.info_collect_config ) ) { printf( "Info collector init error" ); return -1; } pthread_attr_init( &attr ); pthread_attr_setstacksize( &attr, 32 * 4096 ); pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ); while ( 1 ) /* exit is done by db_apply thread */ { sleep( 30 ); EntryProcessor_DumpCurrentStages( ); Dump_Info_Collectors_Stats( ); } for ( i = 0; i < NB_WORKER; i++ ) pthread_join( worker[i], &dummy ); return 0; }
/** * Main daemon routine */ int main( int argc, char **argv ) { int c, option_index = 0; char *bin = basename( argv[0] ); char config_file[MAX_OPT_LEN] = ""; int force_log_level = FALSE; int log_level = 0; int rc; int chgd = 0; char err_msg[4096]; int neg = 0; char badcfg[RBH_PATH_MAX]; /* parse command line options */ while ((c = getopt_long_only(argc, argv, SHORT_OPT_STRING, option_tab, &option_index )) != -1) { switch ( c ) { case '!': neg = 1; break; case 'u': toggle_option(match_user, "user"); prog_options.user = optarg; prog_options.userneg = neg; neg = 0; break; case 'g': toggle_option(match_group, "group"); prog_options.group = optarg; prog_options.groupneg = neg; neg = 0; break; case 'n': toggle_option(match_name, "name"); prog_options.name = optarg; prog_options.nameneg = neg; neg = 0; break; #ifdef _LUSTRE case 'o': toggle_option(match_ost, "ost"); prog_options.ost_idx = str2int(optarg); if (prog_options.ost_idx == (unsigned int)-1) { fprintf(stderr, "invalid ost index '%s': unsigned integer expected\n", optarg); exit(1); } if (neg) { fprintf(stderr, "! () is not supported for ost criteria\n"); exit(1); } break; #endif case 't': toggle_option(match_type, "type"); prog_options.type = opt2type(optarg); if (prog_options.type == NULL) { fprintf(stderr, "invalid type '%s': expected types: "TYPE_HELP".\n", optarg); exit(1); } if (neg) { fprintf(stderr, "! (-not) is not supported for type criteria\n"); exit(1); } break; case 's': toggle_option(match_size, "size"); if (set_size_filter(optarg)) exit(1); if (neg) { fprintf(stderr, "! (-not) is not supported for size criteria\n"); exit(1); } break; case 'A': toggle_option(match_atime, "atime/amin"); if (set_time_filter(optarg, 0, TRUE, atime)) exit(1); if (neg) { fprintf(stderr, "! (-not) is not supported for time criteria\n"); exit(1); } break; case 'a': toggle_option(match_atime, "atime/amin"); if (set_time_filter(optarg, 60, TRUE, atime)) exit(1); if (neg) { fprintf(stderr, "! (-not) is not supported for time criteria\n"); exit(1); } break; case 'C': toggle_option(match_crtime, "crtime"); if (set_time_filter(optarg, 0, TRUE, rh_crtime)) exit(1); if (neg) { fprintf(stderr, "! (-not) is not supported for time criteria\n"); exit(1); } break; case 'M': toggle_option(match_mtime, "mtime/mmin/msec"); if (set_time_filter(optarg, 0, TRUE, mtime)) exit(1); if (neg) { fprintf(stderr, "! (-not) is not supported for time criteria\n"); exit(1); } break; case 'm': toggle_option(match_mtime, "mtime/mmin/msec"); if (set_time_filter(optarg, 60, FALSE, mtime)) /* don't allow suffix (multiplier is 1min) */ exit(1); if (neg) { fprintf(stderr, "! (-not) is not supported for time criteria\n"); exit(1); } break; case 'z': toggle_option(match_mtime, "mtime/mmin/msec"); if (set_time_filter(optarg, 1, FALSE, mtime)) /* don't allow suffix (multiplier is 1sec) */ exit(1); if (neg) { fprintf(stderr, "! (-not) is not supported for time criteria\n"); exit(1); } break; case OPT_ST_CTIME: toggle_option(match_st_ctime, "st-ctime"); if (set_time_filter(optarg, 0, TRUE, stat_ctime)) exit(1); if (neg) { fprintf(stderr, "! (-not) is not supported for time criteria\n"); exit(1); } break; case OPT_ST_MTIME: toggle_option(match_st_mtime, "st-mtime"); if (set_time_filter(optarg, 0, TRUE, stat_mtime)) exit(1); if (neg) { fprintf(stderr, "! (-not) is not supported for time criteria\n"); exit(1); } break; case OPT_ST_ATIME: toggle_option(match_st_atime, "st-atime"); if (set_time_filter(optarg, 0, TRUE, stat_atime)) exit(1); if (neg) { fprintf(stderr, "! (-not) is not supported for time criteria\n"); exit(1); } break; #ifdef ATTR_INDEX_status case 'S': toggle_option(match_status, "status"); prog_options.status = status2dbval(optarg); if ( prog_options.status == (file_status_t)-1 ) { fprintf(stderr, "Unknown status '%s'. Allowed status: %s.\n", optarg, allowed_status()); exit(1); } prog_options.statusneg = neg; neg = 0; break; #endif case 'l': prog_options.ls = 1; disp_mask = DISPLAY_MASK; if (neg) { fprintf(stderr, "! (-not) unexpected before -l option\n"); exit(1); } break; case 'e': prog_options.lsstat = 1; disp_mask = LSSTAT_MASK; if (neg) { fprintf(stderr, "! (-not) unexpected before -e option\n"); exit(1); } break; #ifdef _LUSTRE case OPT_LSOST: prog_options.lsost = 1; disp_mask = LSOST_MASK; if (neg) { fprintf(stderr, "! (-not) unexpected before -lsost option\n"); exit(1); } break; #endif case 'f': strncpy( config_file, optarg, MAX_OPT_LEN ); if (neg) { fprintf(stderr, "! (-not) unexpected before -f option\n"); exit(1); } break; case 'd': force_log_level = TRUE; log_level = str2debuglevel( optarg ); if ( log_level == -1 ) { fprintf(stderr, "Unsupported log level '%s'. CRIT, MAJOR, EVENT, VERB, DEBUG or FULL expected.\n", optarg); exit(1); } if (neg) { fprintf(stderr, "! (-not) unexpected before -d option\n"); exit(1); } break; case 'b': prog_options.bulk = 1; break; case 'h': display_help( bin ); exit( 0 ); break; case 'V': display_version( bin ); exit( 0 ); break; case ':': case '?': default: display_help( bin ); exit( 1 ); break; } } /* get default config file, if not specified */ if ( SearchConfig( config_file, config_file, &chgd, badcfg ) != 0 ) { fprintf(stderr, "No config file (or too many) found matching %s\n", badcfg); exit(2); } else if (chgd) { fprintf(stderr, "Using config file '%s'.\n", config_file ); } /* only read ListMgr config */ if ( ReadRobinhoodConfig( 0, config_file, err_msg, &config, FALSE ) ) { fprintf( stderr, "Error reading configuration file '%s': %s\n", config_file, err_msg ); exit( 1 ); } process_config_file = config_file; /* set global configuration */ global_config = config.global_config; /* set policies info */ policies = config.policies; if ( force_log_level ) config.log_config.debug_level = log_level; else config.log_config.debug_level = LVL_MAJOR; /* no event message */ /* Set logging to stderr */ strcpy( config.log_config.log_file, "stderr" ); strcpy( config.log_config.report_file, "stderr" ); strcpy( config.log_config.alert_file, "stderr" ); /* Initialize logging */ rc = InitializeLogs( bin, &config.log_config ); if ( rc ) { fprintf( stderr, "Error opening log files: rc=%d, errno=%d: %s\n", rc, errno, strerror( errno ) ); exit( rc ); } /* Initialize filesystem access */ rc = InitFS(); if (rc) exit(rc); /* Initialize list manager */ rc = ListMgr_Init( &config.lmgr_config, TRUE ); if ( rc ) { DisplayLog( LVL_CRIT, FIND_TAG, "Error %d initializing list manager", rc ); exit( rc ); } else DisplayLog( LVL_DEBUG, FIND_TAG, "ListManager successfully initialized" ); if (CheckLastFS( ) != 0) exit(1); /* Initialize UID/GID cache. */ InitUidGid_Cache(); /* Create database access */ rc = ListMgr_InitAccess(&lmgr); if (rc) { DisplayLog( LVL_CRIT, FIND_TAG, "Error %d: cannot connect to database", rc ); exit(rc); } if (argc == optind) { if (prog_options.bulk) { DisplayLog(LVL_DEBUG, FIND_TAG, "Performing bulk request on DB"); mkfilters(FALSE); /* keep dirs */ return list_bulk(); } else { char *id = config.global_config.fs_path; mkfilters(TRUE); /* exclude dirs */ /* no path specified, list all entries */ rc = list_content(&id, 1); } } else { if (prog_options.bulk) fprintf(stderr, "No path argument expected with '-bulk' option. Option ignored.\n"); mkfilters(TRUE); /* exclude dirs */ rc = list_content(argv+optind, argc-optind); } ListMgr_CloseAccess( &lmgr ); return rc; }
int main(int argc, char **argv) { unsigned int i; uid_t u; gid_t g; unsigned int c; struct timeval tinit, tcurr, tdiff, tlast = {0}; struct timeval tref_u, tref_g = {0}; float ratio; InitUidGid_Cache(); printf("Reference test of getpwuid (%u items)\n", MAX_UID); gettimeofday(&tinit, NULL); for (i = 0; i <= MAX_UID/10; i++) for (u = 0; u < 10; u++) getpwuid(u); gettimeofday(&tcurr, NULL); timersub(&tcurr, &tinit, &tdiff); tref_u = tdiff; printf("Elapsed time: %ld.%06ld (%.1f/s)\n", tdiff.tv_sec, tdiff.tv_usec, MAX_UID / (tdiff.tv_sec + tdiff.tv_usec/1000000.0)); printf("\nReference test of getgrgid (%u items)\n", MAX_GID); gettimeofday(&tinit, NULL); for (i = 0; i <= MAX_GID/10; i++) for (u = 0; u < 10; u++) getgrgid(u); gettimeofday(&tcurr, NULL); timersub(&tcurr, &tinit, &tdiff); tref_g = tdiff; printf("Elapsed time: %ld.%06ld (%.1f/s)\n", tdiff.tv_sec, tdiff.tv_usec, MAX_GID / (tdiff.tv_sec + tdiff.tv_usec/1000000.0)); printf("\nTest of password cache\n"); gettimeofday(&tinit, NULL); for (i = 0; i <= 10; i++) { c = 0; for (u = 0; u < MAX_UID; u++) { const struct passwd *ppw; ppw = GetPwUid(u); if (ppw) c++; } gettimeofday(&tcurr, NULL); timersub(&tcurr, &tinit, &tdiff); if (i == 0) tlast = tdiff; printf("loop %u, %u items: %lu.%06lu\n", i, c, tdiff.tv_sec, tdiff.tv_usec); if (i == 0) { printf(" Insertion rate: %ld.%06ld (%.1f/s)\n", tdiff.tv_sec, tdiff.tv_usec, MAX_UID / (tdiff.tv_sec + tdiff.tv_usec/1000000.0)); } else if (i == 1) { printf(" Elapsed time: %ld.%06ld (%.1f/s)\n", tdiff.tv_sec, tdiff.tv_usec, MAX_UID / (tdiff.tv_sec + tdiff.tv_usec/1000000.0)); ratio = (tlast.tv_sec*1000000.0 + tlast.tv_usec)/(tdiff.tv_sec*1000000.0 + tdiff.tv_usec); printf(" SPEED-UP (vs insert): x%.2f\n", ratio); ratio = (tref_u.tv_sec*1000000.0 + tref_u.tv_usec)/(tdiff.tv_sec*1000000.0 + tdiff.tv_usec); printf(" SPEED-UP (vs ref): x%.2f\n", ratio); } tinit = tcurr; } /* Now, check that the values returned are correct */ for (u = 0; u < MAX_UID; u++) { const struct passwd *ppw; char buf[50]; ppw = GetPwUid(u); assert(ppw != NULL); assert(ppw->pw_uid == u); sprintf(buf, "%ld", (long)u); assert(strcmp(ppw->pw_name, buf) == 0); } assert(GetPwUid(MAX_UID) == NULL); printf("\nTest of group cache\n"); gettimeofday(&tinit, NULL); for (i = 0; i <= 10; i++) { c = 0; for (g = 0; g < MAX_GID; g++) { const struct group *pgr; pgr = GetGrGid(g); if (pgr) c++; } gettimeofday(&tcurr, NULL); timersub(&tcurr, &tinit, &tdiff); if (i == 0) tlast = tdiff; printf("loop %u, %u items: %lu.%06lu\n", i, c, tdiff.tv_sec, tdiff.tv_usec); if (i == 0) { printf(" Insertion rate: %ld.%06ld (%.1f/s)\n", tdiff.tv_sec, tdiff.tv_usec, MAX_GID / (tdiff.tv_sec + tdiff.tv_usec/1000000.0)); } else if (i == 1) { /* compute speedup */ ratio = (tlast.tv_sec*1000000.0 + tlast.tv_usec)/(tdiff.tv_sec*1000000.0 + tdiff.tv_usec); printf(" SPEED-UP (vs insert): x%.2f\n", ratio); ratio = (tref_g.tv_sec*1000000.0 + tref_g.tv_usec)/(tdiff.tv_sec*1000000.0 + tdiff.tv_usec); printf(" SPEED-UP (vs ref): x%.2f\n", ratio); printf(" Elapsed time: %ld.%06ld (%.1f/s)\n", tdiff.tv_sec, tdiff.tv_usec, MAX_GID / (tdiff.tv_sec + tdiff.tv_usec/1000000.0)); } tinit = tcurr; } /* Now, check that the values returned are correct */ for (g = 0; g < MAX_GID; g++) { const struct group *pgr; char buf[50]; pgr = GetGrGid(g); assert(pgr != NULL); assert(pgr->gr_gid == g); sprintf(buf, "%ld", (long)g); assert(strcmp(pgr->gr_name, buf) == 0); } assert(GetGrGid(MAX_GID) == NULL); printf("Stats:\n"); printf(" password cache hit=%d, miss=%d\n", pw_nb_get, pw_nb_set); printf(" group cache hit=%d, miss=%d\n", gr_nb_get, gr_nb_set); assert(pw_nb_get == 11 * MAX_UID); assert(pw_nb_set == MAX_UID); assert(gr_nb_get == 11 * MAX_GID); assert(gr_nb_set == MAX_GID); return 0; }