NotWritableRecord

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
#include <cassert>
#include <sstream>

#include "Alignment/Geners/interface/AbsArchive.hh"
#include "Alignment/Geners/interface/IOException.hh"

#define GS_STREAM_COPY_BUFFER_SIZE 65536

static void archive_stream_copy(std::istream &in, std::size_t count, std::ostream &out) {
  if (count) {
    const std::size_t bufsize = GS_STREAM_COPY_BUFFER_SIZE;
    char buffer[bufsize];

    bool in_fail = in.fail();
    bool out_fail = out.fail();
    while (count > bufsize && !in_fail && !out_fail) {
      in.read(buffer, bufsize);
      in_fail = in.fail();
      if (!in_fail) {
        out.write(buffer, bufsize);
        out_fail = out.fail();
      }
      count -= bufsize;
    }
    if (!in_fail && !out_fail) {
      in.read(buffer, count);
      if (!in.fail())
        out.write(buffer, count);
    }
  }
}

namespace {
  class NotWritableRecord : public gs::AbsRecord {
  public:
    inline NotWritableRecord(const gs::ClassId &classId, const char *ioPrototype, const char *name, const char *category)
        : gs::AbsRecord(classId, ioPrototype, name, category) {}

    NotWritableRecord() = delete;

  private:
    inline bool writeData(std::ostream &) const override { return false; }
  };
}  // namespace

namespace gs {
  AbsArchive::AbsArchive(const char *name) : name_(name ? name : ""), lastItemId_(0), lastItemLength_(0) {}

  void AbsArchive::addItemToReference(AbsReference &r, const unsigned long long id) const { r.addItemId(id); }

  unsigned long long AbsArchive::copyItem(const unsigned long long id,
                                          AbsArchive *destination,
                                          const char *newName,
                                          const char *newCategory) {
    if (!isReadable())
      throw gs::IOInvalidArgument(
          "In gs::AbsArchive::copyItem: "
          "origin archive is not readable");
    assert(destination);
    if (this == destination)
      throw gs::IOInvalidArgument(
          "In gs::AbsArchive::copyItem: "
          "origin and destination archives are the same");
    AbsArchive &ar(*destination);
    if (!ar.isWritable())
      throw gs::IOInvalidArgument(
          "In gs::AbsArchive::copyItem: "
          "destination archive is not writable");
    std::shared_ptr<const CatalogEntry> entry(catalogEntry(id));
    if (!entry)
      throw gs::IOInvalidArgument(
          "In gs::AbsArchive::copyItem: no item "
          "in the archive with the given id");

    // Position the input stream
    long long sz = 0;
    std::istream &is = inputStream(id, &sz);

    // The following code is similar to the one in the "operator<<"
    // below w.r.t. operations with the output archive
    std::ostream &os = ar.outputStream();
    std::streampos base = os.tellp();
    std::ostream &compressed = ar.compressedStream(os);

    // Transfer the data between the streams
    unsigned long long len;
    if (sz >= 0)
      len = sz;
    else
      len = entry->itemLength();
    archive_stream_copy(is, len, compressed);
    if (is.fail())
      throw IOReadFailure(
          "In gs::AbsArchive::copyItem: "
          "input stream failure");
    if (compressed.fail())
      throw IOWriteFailure(
          "In gs::AbsArchive::copyItem: "
          "output stream failure");
    const unsigned compressCode = ar.flushCompressedRecord(compressed);
    if (os.fail())
      throw IOWriteFailure(
          "In gs::AbsArchive::copyItem: "
          "failed to transfer compressed data");

    // Figure out the record length. Naturally, can't have negative length.
    std::streamoff off = os.tellp() - base;
    const long long delta = off;
    assert(delta >= 0LL);

    // We need to create a record out of the catalog entry we have found
    const char *name = newName;
    if (!name)
      name = entry->name().c_str();
    const char *category = newCategory;
    if (!category)
      category = entry->category().c_str();
    NotWritableRecord record(entry->type(), entry->ioPrototype().c_str(), name, category);

    // Add the record to the catalog
    const unsigned long long id2 = ar.addToCatalog(record, compressCode, delta);
    if (id == 0ULL)
      throw IOWriteFailure(
          "In gs::AbsArchive::copyItem: "
          "failed to add catalog entry");
    ar.lastItemId_ = id2;
    ar.lastItemLength_ = delta;
    return id2;
  }
}  // namespace gs

static std::string local_error_message(gs::AbsArchive &ar, const gs::AbsRecord &record, const char *failedAction) {
  std::ostringstream err;
  err << "In operator<<(gs::AbsArchive& ar, const gs::AbsRecord& record): "
      << "failed to " << failedAction << " to the archive \"" << ar.name() << "\" for item with type \""
      << record.type().name() << "\", name \"" << record.name() << "\", and category \"" << record.category() << '"';
  return err.str();
}

gs::AbsArchive &operator<<(gs::AbsArchive &ar, const gs::AbsRecord &record) {
  // Do not reuse records
  if (record.id())
    throw gs::IOInvalidArgument(
        "In operator<<(gs::AbsArchive& ar, const gs::AbsRecord& record): "
        "records can not be reused");

  // Get the relevant streams. Do not change the order
  // of the next three lines, some code which does
  // not implement compression may actually rely on
  // the fact that the "outputStream()" method
  // is called before "compressedStream()".
  std::ostream &os = ar.outputStream();
  std::streampos base = os.tellp();
  std::ostream &compressed = ar.compressedStream(os);

  // Write the data
  if (!record.writeData(compressed))
    throw gs::IOWriteFailure(local_error_message(ar, record, "write data"));

  const unsigned compressCode = ar.flushCompressedRecord(compressed);
  if (os.fail())
    throw gs::IOWriteFailure(local_error_message(ar, record, "transfer compressed data"));

  // Figure out the record length. Naturally, can't have negative length.
  std::streamoff off = os.tellp() - base;
  const long long delta = off;
  assert(delta >= 0LL);

  // Add the record to the catalog
  const unsigned long long id = ar.addToCatalog(record, compressCode, delta);
  if (id == 0ULL)
    throw gs::IOWriteFailure(local_error_message(ar, record, "add catalog entry"));

  // Mark record as written and give feedback about item length
  record.itemId_ = id;
  record.itemLength_ = delta;

  // Same thing for the archive
  ar.lastItemId_ = id;
  ar.lastItemLength_ = delta;

  return ar;
}