int main(int argc, char *argv[])
{
- struct uuid id = SegmentWriter::generate_uuid();
- string filename = SegmentWriter::format_uuid(id);
-
- printf("Backup UUID: %s\n", filename.c_str());
- FILE *dump = fopen(filename.c_str(), "w");
- if (dump == NULL) {
- fprintf(stderr, "Cannot open file %s: %m\n", filename.c_str());
- return 1;
- }
+ SegmentStore ss(".");
+ SegmentWriter *sw = ss.new_segment();
+ info_dump = sw->new_object();
- FileOutputStream os(dump);
- SegmentWriter sw(os, id);
- info_dump = sw.new_object();
+ string uuid = SegmentWriter::format_uuid(sw->get_uuid());
+ printf("Backup UUID: %s\n", uuid.c_str());
try {
scanfile(".");
fprintf(stderr, "IOException: %s\n", e.getError().c_str());
}
+ delete sw;
+
return 0;
}
return s.contents();
}
-SegmentWriter::SegmentWriter(OutputStream &output, struct uuid u)
+SegmentWriter::SegmentWriter(OutputStream *output, struct uuid u)
: out(output),
id(u),
object_stream(NULL)
{
/* Write out the segment header first. */
static const char signature[] = "LBSSEG0\n";
- out.write(signature, strlen(signature));
- out.write(id.bytes, sizeof(struct uuid));
+ out->write(signature, strlen(signature));
+ out->write(id.bytes, sizeof(struct uuid));
}
SegmentWriter::~SegmentWriter()
// Write out the object table which gives the sizes and locations of all
// objects, and then add the trailing signature, which indicates the end of
// the segment and gives the offset of the object table.
- int64_t index_offset = out.get_pos();
+ int64_t index_offset = out->get_pos();
for (object_table::const_iterator i = objects.begin();
i != objects.end(); ++i) {
- out.write_s64(i->first);
- out.write_s64(i->second);
+ out->write_s64(i->first);
+ out->write_s64(i->second);
}
static const char signature2[] = "LBSEND";
- out.write(signature2, strlen(signature2));
- out.write_s64(index_offset);
- out.write_u32(objects.size());
+ out->write(signature2, strlen(signature2));
+ out->write_s64(index_offset);
+ out->write_u32(objects.size());
+
+ /* The SegmentWriter takes ownership of the OutputStream it is writing to,
+ * and destroys it automatically when done with the segment. */
+ delete out;
}
OutputStream *SegmentWriter::new_object()
if (object_stream)
finish_object();
- object_start_offset = out.get_pos();
- object_stream = new WrapperOutputStream(out);
+ object_start_offset = out->get_pos();
+ object_stream = new WrapperOutputStream(*out);
return object_stream;
}
return string(buf);
}
+
+SegmentStore::SegmentStore(const string &path)
+ : directory(path)
+{
+}
+
+SegmentWriter *SegmentStore::new_segment()
+{
+ struct uuid id = SegmentWriter::generate_uuid();
+ string filename = directory + "/" + SegmentWriter::format_uuid(id);
+
+ FILE *f = fopen(filename.c_str(), "wb");
+ if (f == NULL)
+ throw IOException("Unable to open new segment");
+
+ return new SegmentWriter(new FileOutputStream(f), id);
+}
uint8_t bytes[16];
};
+/* A class which is used to pack multiple objects into a single segment, with a
+ * lookup table to quickly locate each object. Call new_object() to get an
+ * OutputStream to which a new object may be written, and optionally
+ * finish_object() when finished writing the current object. Only one object
+ * may be written to a segment at a time; if multiple objects must be written
+ * concurrently, they must be to different segments. */
class SegmentWriter {
public:
- SegmentWriter(OutputStream &output, struct uuid u);
+ SegmentWriter(OutputStream *output, struct uuid u);
~SegmentWriter();
struct uuid get_uuid() const { return id; }
private:
typedef std::vector<std::pair<int64_t, int64_t> > object_table;
- OutputStream &out;
+ OutputStream *out;
struct uuid id;
int64_t object_start_offset;
object_table objects;
};
+/* A SegmentStore, as the name suggests, is used to store the contents of many
+ * segments. The SegmentStore internally tracks where data should be placed
+ * (such as a local directory or remote storage), and allows new segments to be
+ * easily created as needed. */
+class SegmentStore {
+public:
+ // New segments will be stored in the given directory.
+ SegmentStore(const std::string &path);
+
+ SegmentWriter *new_segment();
+
+private:
+ std::string directory;
+};
+
#endif // _LBS_STORE_H