blob: 385db15722a0073df9e5b07862cac3d04f1d81f3 [file] [edit]
/* -*- Mode: C++; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
#ifndef RR_COMPRESSED_WRITER_H_
#define RR_COMPRESSED_WRITER_H_
#include <pthread.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include "ScopedFd.h"
namespace rr {
/**
* CompressedWriter opens an output file and writes compressed blocks to it.
* Blocks of a fixed but unspecified size (currently 1MB) are compressed.
* Each block of compressed data is written to the file preceded by two
* 32-bit words: the size of the compressed data (excluding block header)
* and the size of the uncompressed data, in that order. See BlockHeader below.
*
* We use multiple threads to perform compression. The threads are
* responsible for the actual data writes. The thread that creates the
* CompressedWriter is the "producer" thread and must also be the caller of
* 'write'. The producer thread may block in 'write' if 'buffer_size' bytes are
* being compressed.
*
* Each data block is compressed independently using zlib.
*/
class CompressedWriter {
public:
CompressedWriter(const std::string& filename, size_t buffer_size,
uint32_t num_threads);
~CompressedWriter();
// Call only on producer thread
bool good() const { return !error; }
// Call only on producer thread.
void write(const void* data, size_t size);
enum Sync { DONT_SYNC, SYNC };
// Call only on producer thread
void close(Sync sync = DONT_SYNC);
struct BlockHeader {
uint32_t compressed_length;
uint32_t uncompressed_length;
};
protected:
enum WaitFlag { WAIT, NOWAIT };
void update_reservation(WaitFlag wait_flag);
static void* compression_thread_callback(void* p);
void compression_thread();
size_t do_compress(uint64_t offset, size_t length, uint8_t* outputbuf,
size_t outputbuf_len);
// Immutable while threads are running
ScopedFd fd;
int block_size;
pthread_mutex_t mutex;
pthread_cond_t cond;
std::vector<pthread_t> threads;
// Carefully shared...
std::vector<uint8_t> buffer;
// BEGIN protected by 'mutex'
/* position in output stream that this thread is currently working on,
* or UINT64_MAX if it's idle */
std::vector<uint64_t> thread_pos;
/* position in output stream of data to dispatch to next thread */
uint64_t next_thread_pos;
/* position in output stream of end of data ready to dispatch */
uint64_t next_thread_end_pos;
bool closing;
bool write_error;
// END protected by 'mutex'
/* producer thread only */
/* Areas in the buffer that have been reserved for write() */
uint64_t producer_reserved_pos;
uint64_t producer_reserved_write_pos;
uint64_t producer_reserved_upto_pos;
bool error;
};
} // namespace rr
#endif /* RR_COMPRESSED_WRITER_H_ */