void rar_check_multi_vomule (FrCommand *comm) { GFile *file; char buffer[11]; file = g_file_new_for_path (comm->filename); if (! g_load_file_in_buffer (file, buffer, 11, NULL)) { g_object_unref (file); return; } if (memcmp (buffer, "Rar!", 4) != 0) return; if ((buffer[10] & 0x01) == 0x01) { char *volume_name = NULL; char *name; name = g_filename_to_utf8 (file_name_from_path (comm->filename), -1, NULL, NULL, NULL); volume_name = get_first_volume_name (name, "^(.*\\.part)([0-9]+)(\\.rar)$", FIRST_VOLUME_IS_001); if (volume_name == NULL) volume_name = get_first_volume_name (name, "^(.*\\.r)([0-9]+)$", FIRST_VOLUME_IS_RAR); if (volume_name == NULL) volume_name = get_first_volume_name (name, "^(.*\\.)([0-9]+)$", FIRST_VOLUME_IS_001); if (volume_name != NULL) { GFile *parent; GFile *child; char *volume_filename; parent = g_file_get_parent (file); child = g_file_get_child (parent, volume_name); volume_filename = g_file_get_path (child); fr_command_set_multi_volume (comm, volume_filename); g_free (volume_filename); g_object_unref (child); g_object_unref (parent); } g_free (name); } g_object_unref (file); }
/** controlling daemon main loop */ static int main_loop(struct program_params *pp) { int ret; const char *lv_name = get_first_volume_name(pp); while (!stop) { // if move daemon is working, wait 5 minutes, start from beginning switch(move_daemon_status(pp, lv_name)) { case PVMOVE_WORKING: sleep(get_pvwait(pp, lv_name)); continue; break; case PVMOVE_IDLE: break; /* do nothing, continue */ default: fprintf(stderr, "Unknown response from move_daemon_status()\n"); goto no_cleanup; break; } // refresh stats, read new stats from file struct extent_stats *es = NULL; ret = get_volume_stats(pp, lv_name, &es); if (ret) { fprintf(stderr, "get_extent_stats error\n"); break; } // get most used min(100,free_space) extents (read and write multipliers from // config file), check if they're on fast or slow storage // move hot extents from slow storage, queue the move in move daemon // continue if move queued for (int tier=0; tier<TIER_MAX; tier++) { if (!lower_tiers_exist(pp, lv_name, tier)) break; off_t free_space = get_avaiable_space(pp, lv_name, tier); if (free_space < 0) { fprintf(stderr, "get_free_space error\n"); goto no_cleanup; } if (free_space == 0) continue; // always leave 5 extents worth of free space so that we always // can move cold extents from higher tier off_t available_extents = free_space / get_extent_size(pp, lv_name) - 5; if (available_extents < 0) available_extents = 0; struct extents *ext = NULL; // get next hottest min(100, free_space) extents size_t max_extents = 100; if (max_extents > available_extents) max_extents = available_extents; ret = extents_selector(es, &ext, pp, lv_name, tier, max_extents, ES_HOT); if (ret) { fprintf(stderr, "extents_selector error\n"); goto no_cleanup; } if (!ext->length) { free_extents(ext); continue; } printf("Moving extents to higher tier\n"); // move them from slow storage, // until no space left ret = queue_extents_move(ext, pp, lv_name, tier); if (ret) { fprintf(stderr, "Can't queue extents move\n"); goto no_cleanup; } free_extents(ext); if (!stop) sleep(get_pvwait(pp, lv_name)); // continue main loop, free memory before goto cont; } printf("All high tiers full\n"); // pin extents to their current physical volumes, this will cause them // to be moved only when the temperature difference is large ret = add_pinning_scores(es, pp, lv_name); if (ret) { fprintf(stderr, "can't add pining scores\n"); goto no_cleanup; } // If there are blocks in slow storage with higher // score than ones in fast storage, move 10 worst extents from fast to slow // if move queued, continue struct extents *prev_tier_max = NULL; int prev_tier = -1; for (int tier = TIER_MAX; tier >= 0; tier--) { off_t free_space = get_avaiable_space(pp, lv_name, tier); if (free_space < 0) { fprintf(stderr, "get_avaiable_space error\n"); goto no_cleanup; } if (!free_space) { if (higher_tiers_exist(pp, lv_name, tier)) continue; else break; } struct extents *curr_tier_min = NULL; printf("trying to move cold extents from tier %i\n", tier); if (!prev_tier_max) { // get base line extents ret = extents_selector(es, &prev_tier_max, pp, lv_name, tier-1, 5, ES_HOT); if (ret) { fprintf(stderr, "extent_selector error\n"); goto no_cleanup; } prev_tier = tier; continue; } ret = extents_selector(es, &curr_tier_min, pp, lv_name, tier, 5, ES_COLD); if (ret) { fprintf(stderr, "%s:%i: extent_selector error\n", __FILE__, __LINE__); goto no_cleanup; } printf("low tier best: %f\n", prev_tier_max->extents[0]->score); printf("high tier worst: %f\n", curr_tier_min->extents[0]->score); // check if extents in lower tier are hotter if (compare_extents(prev_tier_max, curr_tier_min) > 0) { float prev_score = get_extent_score(get_extent(prev_tier_max, 0)); float curr_score = get_extent_score(get_extent(curr_tier_min, 0)); // don't move more extents that would push very hot extents // to low tier or cold extents to higher tier when there is // more cold extents to swap than hotter and vice-versa int prev_count = count_extents(prev_tier_max, curr_score, ES_COLD); int curr_count = count_extents(curr_tier_min, prev_score, ES_HOT); int move_extents = (prev_count > curr_count)?curr_count:prev_count; truncate_extents(prev_tier_max, move_extents); truncate_extents(curr_tier_min, move_extents); // queue move of extents that remain ret = queue_extents_move(prev_tier_max, pp, lv_name, tier); if (ret) { fprintf(stderr, "%s:%i: queue extents failed\n", __FILE__, __LINE__); goto no_cleanup; } ret = queue_extents_move(curr_tier_min, pp, lv_name, prev_tier); if (ret) { fprintf(stderr, "%s:%i: queue extents failed\n", __FILE__, __LINE__); goto no_cleanup; } } else { printf("Nothing to do\n"); } free_extents(curr_tier_min); free_extents(prev_tier_max); prev_tier_max = NULL; // remember previous tier extents ret = extents_selector(es, &prev_tier_max, pp, lv_name, tier, 5, ES_HOT); if (ret) { fprintf(stderr, "%s:%i: Extent_selector error\n", __FILE__, __LINE__); goto no_cleanup; } prev_tier = tier; } // wait 10 minutes if (!stop) sleep(get_check_wait(pp, lv_name)); cont: free_extent_stats(es); } no_cleanup: if (stop) return 0; else return 1; }
int main(int argc, char **argv) { int ret = 0; struct activity_stats *activ = NULL; struct thread_param *tp = malloc(sizeof(struct thread_param)); assert(tp); struct lvmtscd_params pp = { 0 }; if (parse_arguments(argc, argv, &pp)) { free(tp); return 1; } pp.pp = new_program_params(); if(!pp.pp) { fprintf(stderr, "Out of memory error\n"); exit(1); } free(pp.pp->conf_file_path); pp.pp->conf_file_path = pp.config_file; ret = read_config(pp.pp); if(ret) { free_program_params(pp.pp); exit(1); } const char *vol_name = get_first_volume_name(pp.pp); if(!pp.lv_dev_name) asprintf(&pp.lv_dev_name, "/dev/%s/%s", get_volume_vg(pp.pp, vol_name), get_volume_lv(pp.pp, vol_name)); //activ = new_activity_stats_s(1<<10); // assume 2^11 extents (40GiB) if(read_activity_stats(&activ, pp.file)) { fprintf(stderr, "Can't read \"%s\". Ignoring.\n", pp.file); activ = new_activity_stats_s(1<<10); // assume 2^11 extents (40GiB) } if (pp.daemonize) daemonize(); signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); signal(SIGHUP, ignoreHandler); tp->activ = activ; tp->delay = pp.delay; tp->file = pp.file; tp->ender = &programEnd; pthread_attr_t pt_attr; pthread_t thread; if (pthread_attr_init(&pt_attr)) { fprintf(stderr, "Can't initialize thread attribute\n"); return 1; } if(pthread_create(&thread, &pt_attr, &disk_write_worker, tp)) { fprintf(stderr, "Can't create thread\n"); return 1; } if (collect_trace_points(pp.lv_dev_name, activ, pp.granularity, pp.esize, &programEnd)) { fprintf(stderr, "Error while tracing"); ret = 1; } fprintf(stderr, "Writing activity stats..."); union sigval sigArg = {.sival_int=0}; pthread_sigqueue(thread, SIGHUP, sigArg); void *thret; pthread_join(thread, &thret); destroy_activity_stats(activ); free_program_params(pp.pp); fprintf(stderr, "done\n"); return ret; }