/* This file is part of Jellyfish.
Jellyfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jellyfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jellyfish. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace err = jellyfish::err;
using std::chrono::system_clock;
using std::chrono::duration;
using std::chrono::duration_cast;
template
inline double as_seconds(DtnType dtn) { return duration_cast>(dtn).count(); }
static bc_main_cmdline args; // Command line switches and arguments
typedef std::vector file_vector;
using jellyfish::mer_dna;
using jellyfish::mer_dna_bloom_counter;
typedef jellyfish::mer_overlap_sequence_parser > sequence_parser;
typedef jellyfish::mer_iterator mer_iterator;
template
class mer_bloom_counter : public jellyfish::thread_exec {
int nb_threads_;
mer_dna_bloom_counter& filter_;
jellyfish::stream_manager streams_;
sequence_parser parser_;
public:
mer_bloom_counter(int nb_threads, mer_dna_bloom_counter& filter,
PathIterator file_begin, PathIterator file_end,
PathIterator pipe_begin, PathIterator pipe_end,
uint32_t concurent_files) :
filter_(filter),
streams_(file_begin, file_end, pipe_begin, pipe_end, concurent_files),
parser_(jellyfish::mer_dna::k(), streams_.nb_streams(), 3 * nb_threads, 4096, streams_)
{ }
virtual void start(int thid) {
for(mer_iterator mers(parser_, args.canonical_flag) ; mers; ++mers) {
filter_.insert(*mers);
}
}
};
// If get a termination signal, kill the manager and then kill myself.
static pid_t manager_pid = 0;
static void signal_handler(int sig) {
if(manager_pid)
kill(manager_pid, SIGTERM);
signal(sig, SIG_DFL);
kill(getpid(), sig);
_exit(EXIT_FAILURE); // Should not be reached
}
int bc_main(int argc, char *argv[])
{
auto start_time = system_clock::now();
jellyfish::file_header header;
header.fill_standard();
header.set_cmdline(argc, argv);
args.parse(argc, argv);
mer_dna::k(args.mer_len_arg);
std::unique_ptr generator_manager;
if(args.generator_given) {
auto gm =
new jellyfish::generator_manager(args.generator_arg, args.Generators_arg,
args.shell_given ? args.shell_arg : (const char*)0);
generator_manager.reset(gm);
generator_manager->start();
manager_pid = generator_manager->pid();
struct sigaction act;
memset(&act, '\0', sizeof(act));
act.sa_handler = signal_handler;
assert(sigaction(SIGTERM, &act, 0) == 0);
}
header.canonical(args.canonical_flag);
std::ofstream output(args.output_arg);
if(!output.good())
err::die(err::msg() << "Can't open output file '" << args.output_arg << "'");
header.format("bloomcounter");
header.key_len(args.mer_len_arg * 2);
jellyfish::hash_pair hash_fns;
header.matrix(hash_fns.m1, 1);
header.matrix(hash_fns.m2, 2);
mer_dna_bloom_counter filter(args.fpr_arg, args.size_arg, hash_fns);
header.size(filter.m());
header.nb_hashes(filter.k());
header.write(output);
auto after_init_time = system_clock::now();
// Iterators to the multi pipe paths. If no generator manager,
// generate an empty range.
auto pipes_begin = generator_manager.get() ? generator_manager->pipes().begin() : args.file_arg.end();
auto pipes_end = (bool)generator_manager ? generator_manager->pipes().end() : args.file_arg.end();
mer_bloom_counter counter(args.threads_arg, filter,
args.file_arg.begin(), args.file_arg.end(),
pipes_begin, pipes_end, args.Files_arg);
counter.exec_join(args.threads_arg);
// If we have a manager, wait for it
if(generator_manager) {
signal(SIGTERM, SIG_DFL);
manager_pid = 0;
if(!generator_manager->wait())
err::die("Some generator commands failed");
generator_manager.reset();
}
auto after_count_time = system_clock::now();
filter.write_bits(output);
output.close();
auto after_dump_time = system_clock::now();
if(args.timing_given) {
std::ofstream timing_file(args.timing_arg);
timing_file << "Init " << as_seconds(after_init_time - start_time) << "\n"
<< "Counting " << as_seconds(after_count_time - after_init_time) << "\n"
<< "Writing " << as_seconds(after_dump_time - after_count_time) << "\n";
}
return 0;
}