<commit_before>//===-- Serialization.cpp - Binary serialization of index data ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Serialization.h"
#include "Index.h"
#include "RIFF.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"

using namespace llvm;
namespace clang {
namespace clangd {
namespace {
Error makeError(const Twine &Msg) {
  return make_error<StringError>(Msg, inconvertibleErrorCode());
}

// IO PRIMITIVES
// We use little-endian 32 bit ints, sometimes with variable-length encoding.
//
// Variable-length int encoding (varint) uses the bottom 7 bits of each byte
// to encode the number, and the top bit to indicate whether more bytes follow.
// e.g. 9a 2f means [0x1a and keep reading, 0x2f and stop].
// This represents 0x1a | 0x2f<<7 = 6042.
// A 32-bit integer takes 1-5 bytes to encode; small numbers are more compact.

// Reads binary data from a StringRef, and keeps track of position.
class Reader {
  const char *Begin, *End;
  bool Err;

public:
  Reader(StringRef Data) : Begin(Data.begin()), End(Data.end()) {}
  // The "error" bit is set by reading past EOF or reading invalid data.
  // When in an error state, reads may return zero values: callers should check.
  bool err() const { return Err; }
  // Did we read all the data, or encounter an error?
  bool eof() const { return Begin == End || Err; }
  // All the data we didn't read yet.
  StringRef rest() const { return StringRef(Begin, End - Begin); }

  uint8_t consume8() {
    if (LLVM_UNLIKELY(Begin == End)) {
      Err = true;
      return 0;
    }
    return *Begin++;
  }

  uint32_t consume32() {
    if (LLVM_UNLIKELY(Begin + 4 > End)) {
      Err = true;
      return 0;
    }
    auto Ret = support::endian::read32le(Begin);
    Begin += 4;
    return Ret;
  }

  StringRef consume(int N) {
    if (LLVM_UNLIKELY(Begin + N > End)) {
      Err = true;
      return StringRef();
    }
    StringRef Ret(Begin, N);
    Begin += N;
    return Ret;
  }

  uint32_t consumeVar() {
    constexpr static uint8_t More = 1 << 7;
    uint8_t B = consume8();
    if (LLVM_LIKELY(!(B & More)))
      return B;
    uint32_t Val = B & ~More;
    for (int Shift = 7; B & More && Shift < 32; Shift += 7) {
      B = consume8();
      Val |= (B & ~More) << Shift;
    }
    return Val;
  }

  StringRef consumeString(ArrayRef<StringRef> Strings) {
    auto StringIndex = consumeVar();
    if (LLVM_UNLIKELY(StringIndex >= Strings.size())) {
      Err = true;
      return StringRef();
    }
    return Strings[StringIndex];
  }

  SymbolID consumeID() {
    StringRef Raw = consume(SymbolID::RawSize); // short if truncated.
    return LLVM_UNLIKELY(err()) ? SymbolID() : SymbolID::fromRaw(Raw);
  }
};

void write32(uint32_t I, raw_ostream &OS) {
  char buf[4];
  support::endian::write32le(buf, I);
  OS.write(buf, sizeof(buf));
}

void writeVar(uint32_t I, raw_ostream &OS) {
  constexpr static uint8_t More = 1 << 7;
  if (LLVM_LIKELY(I < 1 << 7)) {
    OS.write(I);
    return;
  }
  for (;;) {
    OS.write(I | More);
    I >>= 7;
    if (I < 1 << 7) {
      OS.write(I);
      return;
    }
  }
}

// STRING TABLE ENCODING
// Index data has many string fields, and many strings are identical.
// We store each string once, and refer to them by index.
//
// The string table's format is:
//   - UncompressedSize : uint32 (or 0 for no compression)
//   - CompressedData   : byte[CompressedSize]
//
// CompressedData is a zlib-compressed byte[UncompressedSize].
// It contains a sequence of null-terminated strings, e.g. "foo\0bar\0".
// These are sorted to improve compression.

// Maps each string to a canonical representation.
// Strings remain owned externally (e.g. by SymbolSlab).
class StringTableOut {
  DenseSet<StringRef> Unique;
  std::vector<StringRef> Sorted;
  // Since strings are interned, look up can be by pointer.
  DenseMap<std::pair<const char *, size_t>, unsigned> Index;

public:
  StringTableOut() {
    // Ensure there's at least one string in the table.
    // Table size zero is reserved to indicate no compression.
    Unique.insert("");
  }
  // Add a string to the table. Overwrites S if an identical string exists.
  void intern(StringRef &S) { S = *Unique.insert(S).first; };
  // Finalize the table and write it to OS. No more strings may be added.
  void finalize(raw_ostream &OS) {
    Sorted = {Unique.begin(), Unique.end()};
    std::sort(Sorted.begin(), Sorted.end());
    for (unsigned I = 0; I < Sorted.size(); ++I)
      Index.try_emplace({Sorted[I].data(), Sorted[I].size()}, I);

    std::string RawTable;
    for (StringRef S : Sorted) {
      RawTable.append(S);
      RawTable.push_back(0);
    }
    if (zlib::isAvailable()) {
      SmallString<1> Compressed;
      cantFail(zlib::compress(RawTable, Compressed));
      write32(RawTable.size(), OS);
      OS << Compressed;
    } else {
      write32(0, OS); // No compression.
      OS << RawTable;
    }
  }
  // Get the ID of an string, which must be interned. Table must be finalized.
  unsigned index(StringRef S) const {
    assert(!Sorted.empty() && "table not finalized");
    assert(Index.count({S.data(), S.size()}) && "string not interned");
    return Index.find({S.data(), S.size()})->second;
  }
};

struct StringTableIn {
  BumpPtrAllocator Arena;
  std::vector<StringRef> Strings;
};

Expected<StringTableIn> readStringTable(StringRef Data) {
  Reader R(Data);
  size_t UncompressedSize = R.consume32();
  if (R.err())
    return makeError("Truncated string table");

  StringRef Uncompressed;
  SmallString<1> UncompressedStorage;
  if (UncompressedSize == 0) // No compression
    Uncompressed = R.rest();
  else {
    if (Error E = llvm::zlib::uncompress(R.rest(), UncompressedStorage,
                                         UncompressedSize))
      return std::move(E);
    Uncompressed = UncompressedStorage;
  }

  StringTableIn Table;
  StringSaver Saver(Table.Arena);
  R = Reader(Uncompressed);
  for (Reader R(Uncompressed); !R.eof();) {
    auto Len = R.rest().find(0);
    if (Len == StringRef::npos)
      return makeError("Bad string table: not null terminated");
    Table.Strings.push_back(Saver.save(R.consume(Len)));
    R.consume8();
  }
  if (R.err())
    return makeError("Truncated string table");
  return std::move(Table);
}

// SYMBOL ENCODING
// Each field of clangd::Symbol is encoded in turn (see implementation).
//  - StringRef fields encode as varint (index into the string table)
//  - enums encode as the underlying type
//  - most numbers encode as varint

void writeLocation(const SymbolLocation &Loc, const StringTableOut &Strings,
                   raw_ostream &OS) {
  writeVar(Strings.index(Loc.FileURI), OS);
  for (const auto &Endpoint : {Loc.Start, Loc.End}) {
    writeVar(Endpoint.Line, OS);
    writeVar(Endpoint.Column, OS);
  }
}

SymbolLocation readLocation(Reader &Data, ArrayRef<StringRef> Strings) {
  SymbolLocation Loc;
  Loc.FileURI = Data.consumeString(Strings);
  for (auto *Endpoint : {&Loc.Start, &Loc.End}) {
    Endpoint->Line = Data.consumeVar();
    Endpoint->Column = Data.consumeVar();
  }
  return Loc;
}

void writeSymbol(const Symbol &Sym, const StringTableOut &Strings,
                 raw_ostream &OS) {
  OS << Sym.ID.raw(); // TODO: once we start writing xrefs and posting lists,
                      // symbol IDs should probably be in a string table.
  OS.write(static_cast<uint8_t>(Sym.SymInfo.Kind));
  OS.write(static_cast<uint8_t>(Sym.SymInfo.Lang));
  writeVar(Strings.index(Sym.Name), OS);
  writeVar(Strings.index(Sym.Scope), OS);
  writeLocation(Sym.Definition, Strings, OS);
  writeLocation(Sym.CanonicalDeclaration, Strings, OS);
  writeVar(Sym.References, OS);
  OS.write(static_cast<uint8_t>(Sym.Flags));
  OS.write(static_cast<uint8_t>(Sym.Origin));
  writeVar(Strings.index(Sym.Signature), OS);
  writeVar(Strings.index(Sym.CompletionSnippetSuffix), OS);
  writeVar(Strings.index(Sym.Documentation), OS);
  writeVar(Strings.index(Sym.ReturnType), OS);

  auto WriteInclude = [&](const Symbol::IncludeHeaderWithReferences &Include) {
    writeVar(Strings.index(Include.IncludeHeader), OS);
    writeVar(Include.References, OS);
  };
  writeVar(Sym.IncludeHeaders.size(), OS);
  for (const auto &Include : Sym.IncludeHeaders)
    WriteInclude(Include);
}

Symbol readSymbol(Reader &Data, ArrayRef<StringRef> Strings) {
  Symbol Sym;
  Sym.ID = Data.consumeID();
  Sym.SymInfo.Kind = static_cast<index::SymbolKind>(Data.consume8());
  Sym.SymInfo.Lang = static_cast<index::SymbolLanguage>(Data.consume8());
  Sym.Name = Data.consumeString(Strings);
  Sym.Scope = Data.consumeString(Strings);
  Sym.Definition = readLocation(Data, Strings);
  Sym.CanonicalDeclaration = readLocation(Data, Strings);
  Sym.References = Data.consumeVar();
  Sym.Flags = static_cast<Symbol::SymbolFlag>(Data.consumeVar());
  Sym.Origin = static_cast<SymbolOrigin>(Data.consumeVar());
  Sym.Signature = Data.consumeString(Strings);
  Sym.CompletionSnippetSuffix = Data.consumeString(Strings);
  Sym.Documentation = Data.consumeString(Strings);
  Sym.ReturnType = Data.consumeString(Strings);
  Sym.IncludeHeaders.resize(Data.consumeVar());
  for (auto &I : Sym.IncludeHeaders) {
    I.IncludeHeader = Data.consumeString(Strings);
    I.References = Data.consumeVar();
  }
  return Sym;
}

} // namespace

// FILE ENCODING
// A file is a RIFF chunk with type 'CdIx'.
// It contains the sections:
//   - meta: version number
//   - stri: string table
//   - symb: symbols

// The current versioning scheme is simple - non-current versions are rejected.
// If you make a breaking change, bump this version number to invalidate stored
// data. Later we may want to support some backward compatibility.
constexpr static uint32_t Version = 4;

Expected<IndexFileIn> readIndexFile(StringRef Data) {
  auto RIFF = riff::readFile(Data);
  if (!RIFF)
    return RIFF.takeError();
  if (RIFF->Type != riff::fourCC("CdIx"))
    return makeError("wrong RIFF type");
  StringMap<StringRef> Chunks;
  for (const auto &Chunk : RIFF->Chunks)
    Chunks.try_emplace(StringRef(Chunk.ID.data(), Chunk.ID.size()), Chunk.Data);

  for (StringRef RequiredChunk : {"meta", "stri"})
    if (!Chunks.count(RequiredChunk))
      return makeError("missing required chunk " + RequiredChunk);

  Reader Meta(Chunks.lookup("meta"));
  if (Meta.consume32() != Version)
    return makeError("wrong version");

  auto Strings = readStringTable(Chunks.lookup("stri"));
  if (!Strings)
    return Strings.takeError();

  IndexFileIn Result;
  if (Chunks.count("symb")) {
    Reader SymbolReader(Chunks.lookup("symb"));
    SymbolSlab::Builder Symbols;
    while (!SymbolReader.eof())
      Symbols.insert(readSymbol(SymbolReader, Strings->Strings));
    if (SymbolReader.err())
      return makeError("malformed or truncated symbol");
    Result.Symbols = std::move(Symbols).build();
  }
  return std::move(Result);
}

raw_ostream &operator<<(raw_ostream &OS, const IndexFileOut &Data) {
  assert(Data.Symbols && "An index file without symbols makes no sense!");
  riff::File RIFF;
  RIFF.Type = riff::fourCC("CdIx");

  SmallString<4> Meta;
  {
    raw_svector_ostream MetaOS(Meta);
    write32(Version, MetaOS);
  }
  RIFF.Chunks.push_back({riff::fourCC("meta"), Meta});

  StringTableOut Strings;
  std::vector<Symbol> Symbols;
  for (const auto &Sym : *Data.Symbols) {
    Symbols.emplace_back(Sym);
    visitStrings(Symbols.back(), [&](StringRef &S) { Strings.intern(S); });
  }

  std::string StringSection;
  {
    raw_string_ostream StringOS(StringSection);
    Strings.finalize(StringOS);
  }
  RIFF.Chunks.push_back({riff::fourCC("stri"), StringSection});

  std::string SymbolSection;
  {
    raw_string_ostream SymbolOS(SymbolSection);
    for (const auto &Sym : Symbols)
      writeSymbol(Sym, Strings, SymbolOS);
  }
  RIFF.Chunks.push_back({riff::fourCC("symb"), SymbolSection});

  return OS << RIFF;
}

} // namespace clangd
} // namespace clang
<commit_msg>[clangd] Fix uninit bool in r342888<commit_after>//===-- Serialization.cpp - Binary serialization of index data ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Serialization.h"
#include "Index.h"
#include "RIFF.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"

using namespace llvm;
namespace clang {
namespace clangd {
namespace {
Error makeError(const Twine &Msg) {
  return make_error<StringError>(Msg, inconvertibleErrorCode());
}

// IO PRIMITIVES
// We use little-endian 32 bit ints, sometimes with variable-length encoding.
//
// Variable-length int encoding (varint) uses the bottom 7 bits of each byte
// to encode the number, and the top bit to indicate whether more bytes follow.
// e.g. 9a 2f means [0x1a and keep reading, 0x2f and stop].
// This represents 0x1a | 0x2f<<7 = 6042.
// A 32-bit integer takes 1-5 bytes to encode; small numbers are more compact.

// Reads binary data from a StringRef, and keeps track of position.
class Reader {
  const char *Begin, *End;
  bool Err = false;

public:
  Reader(StringRef Data) : Begin(Data.begin()), End(Data.end()) {}
  // The "error" bit is set by reading past EOF or reading invalid data.
  // When in an error state, reads may return zero values: callers should check.
  bool err() const { return Err; }
  // Did we read all the data, or encounter an error?
  bool eof() const { return Begin == End || Err; }
  // All the data we didn't read yet.
  StringRef rest() const { return StringRef(Begin, End - Begin); }

  uint8_t consume8() {
    if (LLVM_UNLIKELY(Begin == End)) {
      Err = true;
      return 0;
    }
    return *Begin++;
  }

  uint32_t consume32() {
    if (LLVM_UNLIKELY(Begin + 4 > End)) {
      Err = true;
      return 0;
    }
    auto Ret = support::endian::read32le(Begin);
    Begin += 4;
    return Ret;
  }

  StringRef consume(int N) {
    if (LLVM_UNLIKELY(Begin + N > End)) {
      Err = true;
      return StringRef();
    }
    StringRef Ret(Begin, N);
    Begin += N;
    return Ret;
  }

  uint32_t consumeVar() {
    constexpr static uint8_t More = 1 << 7;
    uint8_t B = consume8();
    if (LLVM_LIKELY(!(B & More)))
      return B;
    uint32_t Val = B & ~More;
    for (int Shift = 7; B & More && Shift < 32; Shift += 7) {
      B = consume8();
      Val |= (B & ~More) << Shift;
    }
    return Val;
  }

  StringRef consumeString(ArrayRef<StringRef> Strings) {
    auto StringIndex = consumeVar();
    if (LLVM_UNLIKELY(StringIndex >= Strings.size())) {
      Err = true;
      return StringRef();
    }
    return Strings[StringIndex];
  }

  SymbolID consumeID() {
    StringRef Raw = consume(SymbolID::RawSize); // short if truncated.
    return LLVM_UNLIKELY(err()) ? SymbolID() : SymbolID::fromRaw(Raw);
  }
};

void write32(uint32_t I, raw_ostream &OS) {
  char buf[4];
  support::endian::write32le(buf, I);
  OS.write(buf, sizeof(buf));
}

void writeVar(uint32_t I, raw_ostream &OS) {
  constexpr static uint8_t More = 1 << 7;
  if (LLVM_LIKELY(I < 1 << 7)) {
    OS.write(I);
    return;
  }
  for (;;) {
    OS.write(I | More);
    I >>= 7;
    if (I < 1 << 7) {
      OS.write(I);
      return;
    }
  }
}

// STRING TABLE ENCODING
// Index data has many string fields, and many strings are identical.
// We store each string once, and refer to them by index.
//
// The string table's format is:
//   - UncompressedSize : uint32 (or 0 for no compression)
//   - CompressedData   : byte[CompressedSize]
//
// CompressedData is a zlib-compressed byte[UncompressedSize].
// It contains a sequence of null-terminated strings, e.g. "foo\0bar\0".
// These are sorted to improve compression.

// Maps each string to a canonical representation.
// Strings remain owned externally (e.g. by SymbolSlab).
class StringTableOut {
  DenseSet<StringRef> Unique;
  std::vector<StringRef> Sorted;
  // Since strings are interned, look up can be by pointer.
  DenseMap<std::pair<const char *, size_t>, unsigned> Index;

public:
  StringTableOut() {
    // Ensure there's at least one string in the table.
    // Table size zero is reserved to indicate no compression.
    Unique.insert("");
  }
  // Add a string to the table. Overwrites S if an identical string exists.
  void intern(StringRef &S) { S = *Unique.insert(S).first; };
  // Finalize the table and write it to OS. No more strings may be added.
  void finalize(raw_ostream &OS) {
    Sorted = {Unique.begin(), Unique.end()};
    std::sort(Sorted.begin(), Sorted.end());
    for (unsigned I = 0; I < Sorted.size(); ++I)
      Index.try_emplace({Sorted[I].data(), Sorted[I].size()}, I);

    std::string RawTable;
    for (StringRef S : Sorted) {
      RawTable.append(S);
      RawTable.push_back(0);
    }
    if (zlib::isAvailable()) {
      SmallString<1> Compressed;
      cantFail(zlib::compress(RawTable, Compressed));
      write32(RawTable.size(), OS);
      OS << Compressed;
    } else {
      write32(0, OS); // No compression.
      OS << RawTable;
    }
  }
  // Get the ID of an string, which must be interned. Table must be finalized.
  unsigned index(StringRef S) const {
    assert(!Sorted.empty() && "table not finalized");
    assert(Index.count({S.data(), S.size()}) && "string not interned");
    return Index.find({S.data(), S.size()})->second;
  }
};

struct StringTableIn {
  BumpPtrAllocator Arena;
  std::vector<StringRef> Strings;
};

Expected<StringTableIn> readStringTable(StringRef Data) {
  Reader R(Data);
  size_t UncompressedSize = R.consume32();
  if (R.err())
    return makeError("Truncated string table");

  StringRef Uncompressed;
  SmallString<1> UncompressedStorage;
  if (UncompressedSize == 0) // No compression
    Uncompressed = R.rest();
  else {
    if (Error E = llvm::zlib::uncompress(R.rest(), UncompressedStorage,
                                         UncompressedSize))
      return std::move(E);
    Uncompressed = UncompressedStorage;
  }

  StringTableIn Table;
  StringSaver Saver(Table.Arena);
  R = Reader(Uncompressed);
  for (Reader R(Uncompressed); !R.eof();) {
    auto Len = R.rest().find(0);
    if (Len == StringRef::npos)
      return makeError("Bad string table: not null terminated");
    Table.Strings.push_back(Saver.save(R.consume(Len)));
    R.consume8();
  }
  if (R.err())
    return makeError("Truncated string table");
  return std::move(Table);
}

// SYMBOL ENCODING
// Each field of clangd::Symbol is encoded in turn (see implementation).
//  - StringRef fields encode as varint (index into the string table)
//  - enums encode as the underlying type
//  - most numbers encode as varint

void writeLocation(const SymbolLocation &Loc, const StringTableOut &Strings,
                   raw_ostream &OS) {
  writeVar(Strings.index(Loc.FileURI), OS);
  for (const auto &Endpoint : {Loc.Start, Loc.End}) {
    writeVar(Endpoint.Line, OS);
    writeVar(Endpoint.Column, OS);
  }
}

SymbolLocation readLocation(Reader &Data, ArrayRef<StringRef> Strings) {
  SymbolLocation Loc;
  Loc.FileURI = Data.consumeString(Strings);
  for (auto *Endpoint : {&Loc.Start, &Loc.End}) {
    Endpoint->Line = Data.consumeVar();
    Endpoint->Column = Data.consumeVar();
  }
  return Loc;
}

void writeSymbol(const Symbol &Sym, const StringTableOut &Strings,
                 raw_ostream &OS) {
  OS << Sym.ID.raw(); // TODO: once we start writing xrefs and posting lists,
                      // symbol IDs should probably be in a string table.
  OS.write(static_cast<uint8_t>(Sym.SymInfo.Kind));
  OS.write(static_cast<uint8_t>(Sym.SymInfo.Lang));
  writeVar(Strings.index(Sym.Name), OS);
  writeVar(Strings.index(Sym.Scope), OS);
  writeLocation(Sym.Definition, Strings, OS);
  writeLocation(Sym.CanonicalDeclaration, Strings, OS);
  writeVar(Sym.References, OS);
  OS.write(static_cast<uint8_t>(Sym.Flags));
  OS.write(static_cast<uint8_t>(Sym.Origin));
  writeVar(Strings.index(Sym.Signature), OS);
  writeVar(Strings.index(Sym.CompletionSnippetSuffix), OS);
  writeVar(Strings.index(Sym.Documentation), OS);
  writeVar(Strings.index(Sym.ReturnType), OS);

  auto WriteInclude = [&](const Symbol::IncludeHeaderWithReferences &Include) {
    writeVar(Strings.index(Include.IncludeHeader), OS);
    writeVar(Include.References, OS);
  };
  writeVar(Sym.IncludeHeaders.size(), OS);
  for (const auto &Include : Sym.IncludeHeaders)
    WriteInclude(Include);
}

Symbol readSymbol(Reader &Data, ArrayRef<StringRef> Strings) {
  Symbol Sym;
  Sym.ID = Data.consumeID();
  Sym.SymInfo.Kind = static_cast<index::SymbolKind>(Data.consume8());
  Sym.SymInfo.Lang = static_cast<index::SymbolLanguage>(Data.consume8());
  Sym.Name = Data.consumeString(Strings);
  Sym.Scope = Data.consumeString(Strings);
  Sym.Definition = readLocation(Data, Strings);
  Sym.CanonicalDeclaration = readLocation(Data, Strings);
  Sym.References = Data.consumeVar();
  Sym.Flags = static_cast<Symbol::SymbolFlag>(Data.consumeVar());
  Sym.Origin = static_cast<SymbolOrigin>(Data.consumeVar());
  Sym.Signature = Data.consumeString(Strings);
  Sym.CompletionSnippetSuffix = Data.consumeString(Strings);
  Sym.Documentation = Data.consumeString(Strings);
  Sym.ReturnType = Data.consumeString(Strings);
  Sym.IncludeHeaders.resize(Data.consumeVar());
  for (auto &I : Sym.IncludeHeaders) {
    I.IncludeHeader = Data.consumeString(Strings);
    I.References = Data.consumeVar();
  }
  return Sym;
}

} // namespace

// FILE ENCODING
// A file is a RIFF chunk with type 'CdIx'.
// It contains the sections:
//   - meta: version number
//   - stri: string table
//   - symb: symbols

// The current versioning scheme is simple - non-current versions are rejected.
// If you make a breaking change, bump this version number to invalidate stored
// data. Later we may want to support some backward compatibility.
constexpr static uint32_t Version = 4;

Expected<IndexFileIn> readIndexFile(StringRef Data) {
  auto RIFF = riff::readFile(Data);
  if (!RIFF)
    return RIFF.takeError();
  if (RIFF->Type != riff::fourCC("CdIx"))
    return makeError("wrong RIFF type");
  StringMap<StringRef> Chunks;
  for (const auto &Chunk : RIFF->Chunks)
    Chunks.try_emplace(StringRef(Chunk.ID.data(), Chunk.ID.size()), Chunk.Data);

  for (StringRef RequiredChunk : {"meta", "stri"})
    if (!Chunks.count(RequiredChunk))
      return makeError("missing required chunk " + RequiredChunk);

  Reader Meta(Chunks.lookup("meta"));
  if (Meta.consume32() != Version)
    return makeError("wrong version");

  auto Strings = readStringTable(Chunks.lookup("stri"));
  if (!Strings)
    return Strings.takeError();

  IndexFileIn Result;
  if (Chunks.count("symb")) {
    Reader SymbolReader(Chunks.lookup("symb"));
    SymbolSlab::Builder Symbols;
    while (!SymbolReader.eof())
      Symbols.insert(readSymbol(SymbolReader, Strings->Strings));
    if (SymbolReader.err())
      return makeError("malformed or truncated symbol");
    Result.Symbols = std::move(Symbols).build();
  }
  return std::move(Result);
}

raw_ostream &operator<<(raw_ostream &OS, const IndexFileOut &Data) {
  assert(Data.Symbols && "An index file without symbols makes no sense!");
  riff::File RIFF;
  RIFF.Type = riff::fourCC("CdIx");

  SmallString<4> Meta;
  {
    raw_svector_ostream MetaOS(Meta);
    write32(Version, MetaOS);
  }
  RIFF.Chunks.push_back({riff::fourCC("meta"), Meta});

  StringTableOut Strings;
  std::vector<Symbol> Symbols;
  for (const auto &Sym : *Data.Symbols) {
    Symbols.emplace_back(Sym);
    visitStrings(Symbols.back(), [&](StringRef &S) { Strings.intern(S); });
  }

  std::string StringSection;
  {
    raw_string_ostream StringOS(StringSection);
    Strings.finalize(StringOS);
  }
  RIFF.Chunks.push_back({riff::fourCC("stri"), StringSection});

  std::string SymbolSection;
  {
    raw_string_ostream SymbolOS(SymbolSection);
    for (const auto &Sym : Symbols)
      writeSymbol(Sym, Strings, SymbolOS);
  }
  RIFF.Chunks.push_back({riff::fourCC("symb"), SymbolSection});

  return OS << RIFF;
}

} // namespace clangd
} // namespace clang
<|endoftext|>


<commit_before>//=============================================================================
//File Name: GyroBase.hpp
//Description: Wrapper for a gyro-accelerometer Kalman filter (GyroFilter)
//Author: FRC Team 3512, Spartatroniks
//=============================================================================

/* Usage:
 *
 * This class is a wrapper for a gyro-accelerometer Kalman Filter. Since this
 * class can't possibly know how to interface with every gyro and accelerometer
 * that exists, you'll instead handle your gyro/accelerometer in your own
 * derived class and pass in the required data from them via the pure virtual
 * functions.
 *
 * * To use this interface, derive from this class and override all pure
 *   virtual member functions privately.
 *
 * Function clarifications:
 *   * readGyroX() should return the value of the X-axis of the gyro
 *   * readAccelY() should return the value of the Y-axis of the accelerometer
 *   * getGyroZzero() should return the constant representing the zero point of
 *     the Z-axis of the gyro
 *   * getGyroLSBsPerUnit() should return the number of least significant bits
 *     representing a change in the gyro's value of 1 degree/second. This can
 *     be found in the data sheet for the specific gyro you're using.
 *
 * Misc. Help:
 *   * If your accelerometer or gyro doesn't have one or more of the three
 *     axes, don't inherit the functions related to them. Avoid calling
 *     functions returning data for that respective axis, since it will be
 *     garbage.
 */

#ifndef GYRO_BASE_HPP
#define GYRO_BASE_HPP

#include <Notifier.h>
#include <Synchronized.h>
#include "GyroFilter.hpp"

class GyroBase {
public:
    GyroBase();
    virtual ~GyroBase();

    // Return the internally stored values for gyro angles
    double getXangle();
    double getYangle();
    double getZangle();

    // Used to reset starting angle for the respective axis
    void resetXangle( double newAngle );
    void resetYangle( double newAngle );
    void resetZangle( double newAngle );

    // Return the unbiased rate of the respective axis
    double getXrate();
    double getYrate();
    double getZrate();

protected:
    // Return angle calculated with accelerometer data (returns degrees)
    double getAccelXangle();
    double getAccelYangle();
    double getAccelZangle();

    // Return rate calculated with gyro data
    double getGyroXrate();
    double getGyroYrate();
    double getGyroZrate();

private:
    GyroFilter xFilter;
    GyroFilter yFilter;
    GyroFilter zFilter;

    // Read angle change (usually raw data) from gyro
    virtual int readGyroX();
    virtual int readGyroY();
    virtual int readGyroZ();

    // Read acceleration (usually raw data) from accelerometer
    virtual int readAccelX();
    virtual int readAccelY();
    virtual int readAccelZ();

    // Return zero points for gyro
    virtual double getGyroXzero();
    virtual double getGyroYzero();
    virtual double getGyroZzero();

    // Return zero points for accelerometer
    virtual double getAccelXzero();
    virtual double getAccelYzero();
    virtual double getAccelZzero();

    // Return sensitivity of gyro in least significant bits per degree/second
    virtual double getGyroLSBsPerUnit() = 0;
};

#endif // GYRO_BASE_HPP
<commit_msg>Added more to explanation of GyroBase::getGyroLSBsPerUnit() ; added note about GyroBase class only supporting digital gyros at this time<commit_after>//=============================================================================
//File Name: GyroBase.hpp
//Description: Wrapper for a gyro-accelerometer Kalman filter (GyroFilter)
//Author: FRC Team 3512, Spartatroniks
//=============================================================================

/* Usage:
 *
 * This class is a wrapper for a gyro-accelerometer Kalman Filter. Since this
 * class can't possibly know how to interface with every gyro and accelerometer
 * that exists, you'll instead handle your gyro/accelerometer in your own
 * derived class and pass in the required data from them via the virtual
 * functions. This class is designed for use with a digital (not analog) gyro.
 * TODO: Support analog gyros
 *
 * * To use this interface, derive from this class and override all pure
 *   virtual member functions privately.
 *
 * Function clarifications:
 *   * readGyroX() should return the value of the X-axis of the gyro
 *   * readAccelY() should return the value of the Y-axis of the accelerometer
 *   * getGyroZzero() should return the constant representing the zero point of
 *     the Z-axis of the gyro
 *   * getGyroLSBsPerUnit() should return the number of least significant bits
 *     which represent a change in the gyro's value of 1 degree/second. This
 *     can be found in the data sheet for the specific gyro you're using. Some
 *     data sheets may tell you that one LSB is A degrees/second, or A units
 *     per LSB, in which case 1/A, or 1/A LSBs per unit, would be the value to
 *     return from this function.
 *
 * Misc. Help:
 *   * If your accelerometer or gyro doesn't have one or more of the three
 *     axes, don't inherit the functions related to them. Avoid calling
 *     functions returning data for that respective axis, since it will be
 *     garbage.
 */

#ifndef GYRO_BASE_HPP
#define GYRO_BASE_HPP

#include <Notifier.h>
#include <Synchronized.h>
#include "GyroFilter.hpp"

class GyroBase {
public:
    GyroBase();
    virtual ~GyroBase();

    // Return the internally stored values for gyro angles
    double getXangle();
    double getYangle();
    double getZangle();

    // Used to reset starting angle for the respective axis
    void resetXangle( double newAngle );
    void resetYangle( double newAngle );
    void resetZangle( double newAngle );

    // Return the unbiased rate of the respective axis
    double getXrate();
    double getYrate();
    double getZrate();

protected:
    // Return angle calculated with accelerometer data (returns degrees)
    double getAccelXangle();
    double getAccelYangle();
    double getAccelZangle();

    // Return rate calculated with gyro data
    double getGyroXrate();
    double getGyroYrate();
    double getGyroZrate();

private:
    GyroFilter xFilter;
    GyroFilter yFilter;
    GyroFilter zFilter;

    // Read angle change (usually raw data) from gyro
    virtual int readGyroX();
    virtual int readGyroY();
    virtual int readGyroZ();

    // Read acceleration (usually raw data) from accelerometer
    virtual int readAccelX();
    virtual int readAccelY();
    virtual int readAccelZ();

    // Return zero points for gyro
    virtual double getGyroXzero();
    virtual double getGyroYzero();
    virtual double getGyroZzero();

    // Return zero points for accelerometer
    virtual double getAccelXzero();
    virtual double getAccelYzero();
    virtual double getAccelZzero();

    // Return sensitivity of gyro in least significant bits per degree/second
    virtual double getGyroLSBsPerUnit() = 0;
};

#endif // GYRO_BASE_HPP
<|endoftext|>


<commit_before>/* RapicornSignal
 * Copyright (C) 2005-2006 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#include "rapicornsignal.hh"

namespace Rapicorn {
namespace Signals {

/* --- TrampolineLink --- */
TrampolineLink::~TrampolineLink()
{
  if (next || prev)
    {
      next->prev = prev;
      prev->next = next;
      prev = next = NULL;
    }
}

/* --- SignalBase --- */
bool
SignalBase::EmbeddedLink::operator== (const TrampolineLink &other) const
{
  return false;
}

void
SignalBase::EmbeddedLink::delete_this ()
{
  /* not deleting, because this structure is always embedded as SignalBase::start */
}

} // Signals
} // Rapicorn
<commit_msg>RCORE: fixed disconnected TrampolineLink destruction<commit_after>/* RapicornSignal
 * Copyright (C) 2005-2006 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#include "rapicornsignal.hh"

namespace Rapicorn {
namespace Signals {

/* --- TrampolineLink --- */
TrampolineLink::~TrampolineLink()
{
  if (next || prev)
    {
      // disconnect_equal_link() might have left next and prev != NULL
      prev = next = NULL;
    }
}

/* --- SignalBase --- */
bool
SignalBase::EmbeddedLink::operator== (const TrampolineLink &other) const
{
  return false;
}

void
SignalBase::EmbeddedLink::delete_this ()
{
  /* not deleting, because this structure is always embedded as SignalBase::start */
}

} // Signals
} // Rapicorn
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "bvh_builder_twolevel.h"
#include "bvh_statistics.h"
#include "../builders/bvh_builder_sah.h"
#include "../common/scene_line_segments.h"
#include "../common/scene_triangle_mesh.h"
#include "../common/scene_quad_mesh.h"

#define PROFILE 0
#define MAX_OPEN_SIZE 10000
#define PROFILE_ITERATIONS 200

namespace embree
{
  namespace isa
  {
    template<int N, typename Mesh>
    BVHNBuilderTwoLevel<N,Mesh>::BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, const createMeshAccelTy createMeshAccel)
      : bvh(bvh), objects(bvh->objects), scene(scene), createMeshAccel(createMeshAccel), refs(scene->device), prims(scene->device) {}

    template<int N, typename Mesh>
    BVHNBuilderTwoLevel<N,Mesh>::~BVHNBuilderTwoLevel ()
    {
      for (size_t i=0; i<builders.size(); i++)
	delete builders[i];
    }

    template<int N, typename Mesh>
    void BVHNBuilderTwoLevel<N,Mesh>::build(size_t threadIndex, size_t threadCount)
    {
      /* delete some objects */
      size_t num = scene->size();
      if (num < objects.size()) {
        parallel_for(num, objects.size(), [&] (const range<size_t>& r) {
            for (size_t i=r.begin(); i<r.end(); i++) {
              delete builders[i]; builders[i] = nullptr;
              delete objects[i]; objects[i] = nullptr;
            }
          });
      }

      /* reset memory allocator */
      bvh->alloc.reset();

      /* skip build for empty scene */
      const size_t numPrimitives = scene->getNumPrimitives<Mesh,false>();
      if (numPrimitives == 0) {
        prims.resize(0);
        bvh->set(BVH::emptyNode,empty,0);
        return;
      }

      double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(N) + "BuilderTwoLevel");

#if PROFILE
	profile(2,PROFILE_ITERATIONS,numPrimitives,[&] (ProfileTimer& timer)
        {
#endif

      /* resize object array if scene got larger */
      if (objects.size()  < num) objects.resize(num);
      if (builders.size() < num) builders.resize(num);
      if (refs.size()     < num) refs.resize(num);
      nextRef.store(0);

      /* create of acceleration structures */
      parallel_for(size_t(0), num, [&] (const range<size_t>& r)
      {
        for (size_t objectID=r.begin(); objectID<r.end(); objectID++)
        {
          Mesh* mesh = scene->getSafe<Mesh>(objectID);

          /* verify meshes got deleted properly */
          if (mesh == nullptr || mesh->numTimeSteps != 1) {
            assert(objectID < objects.size () && objects[objectID] == nullptr);
            assert(objectID < builders.size() && builders[objectID] == nullptr);
            continue;
          }

          /* create BVH and builder for new meshes */
          if (objects[objectID] == nullptr)
            createMeshAccel(mesh,(AccelData*&)objects[objectID],builders[objectID]);
        }
      });

      /* parallel build of acceleration structures */
      parallel_for(size_t(0), num, [&] (const range<size_t>& r)
      {
        for (size_t objectID=r.begin(); objectID<r.end(); objectID++)
        {
          /* ignore if no triangle mesh or not enabled */
          Mesh* mesh = scene->getSafe<Mesh>(objectID);
          if (mesh == nullptr || !mesh->isEnabled() || mesh->numTimeSteps != 1)
            continue;

          BVH*     object  = objects [objectID]; assert(object);
          Builder* builder = builders[objectID]; assert(builder);

          /* build object if it got modified */
#if !PROFILE
          if (mesh->isModified())
#endif
            builder->build(0,0);

          /* create build primitive */
          if (!object->getBounds().empty())
            refs[nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root);
        }
      });

      /* fast path for single geometry scenes */
      if (nextRef == 1) {
        bvh->set(refs[0].node,LBBox3fa(refs[0].bounds()),numPrimitives);
        return;
      }

      /* open all large nodes */
      refs.resize(nextRef);
      open_sequential(numPrimitives);

      /* fast path for small geometries */
      if (refs.size() == 1) {
        bvh->set(refs[0].node,LBBox3fa(refs[0].bounds()),numPrimitives);
        return;
      }

      /* compute PrimRefs */
      prims.resize(refs.size());
      const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(),  PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo
      {
        PrimInfo pinfo(empty);
        for (size_t i=r.begin(); i<r.end(); i++) {
          pinfo.add(refs[i].bounds());
          prims[i] = PrimRef(refs[i].bounds(),(size_t)refs[i].node);
        }
        return pinfo;
      }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); });

      /* skip if all objects where empty */
      if (pinfo.size() == 0)
        bvh->set(BVH::emptyNode,empty,0);

      /* otherwise build toplevel hierarchy */
      else
      {
        NodeRef root;
        BVHBuilderBinnedSAH::build<NodeRef>
          (root,
           [&] { return bvh->alloc.threadLocal2(); },
           [&] (const isa::BVHBuilderBinnedSAH::BuildRecord& current, BVHBuilderBinnedSAH::BuildRecord* children, const size_t n, FastAllocator::ThreadLocal2* alloc) -> int
           {
             AlignedNode* node = (AlignedNode*) alloc->alloc0->malloc(sizeof(AlignedNode)); node->clear();
             for (size_t i=0; i<n; i++) {
               node->set(i,children[i].pinfo.geomBounds);
               children[i].parent = (size_t*)&node->child(i);
             }
             *current.parent = bvh->encodeNode(node);
             return 0;
           },
           [&] (const BVHBuilderBinnedSAH::BuildRecord& current, FastAllocator::ThreadLocal2* alloc) -> int
           {
             assert(current.prims.size() == 1);
             *current.parent = (NodeRef) prims[current.prims.begin()].ID();
             return 1;
           },
           [&] (size_t dn) { bvh->scene->progressMonitor(0); },
           prims.data(),pinfo,N,BVH::maxBuildDepthLeaf,N,1,1,1.0f,1.0f);

        bvh->set(root,LBBox3fa(pinfo.geomBounds),numPrimitives);
      }

#if PROFILE
      });
#endif

      bvh->alloc.cleanup();
      bvh->postBuild(t0);
    }

    template<int N, typename Mesh>
    void BVHNBuilderTwoLevel<N,Mesh>::deleteGeometry(size_t geomID)
    {
      if (geomID >= objects.size()) return;
      delete builders[geomID]; builders[geomID] = nullptr;
      delete objects [geomID]; objects [geomID] = nullptr;
    }

    template<int N, typename Mesh>
    void BVHNBuilderTwoLevel<N,Mesh>::clear()
    {
      for (size_t i=0; i<objects.size(); i++)
        if (objects[i]) objects[i]->clear();

      for (size_t i=0; i<builders.size(); i++)
	if (builders[i]) builders[i]->clear();

      refs.clear();
    }

    template<int N, typename Mesh>
    void BVHNBuilderTwoLevel<N,Mesh>::open_sequential(size_t numPrimitives)
    {
      if (refs.size() == 0)
	return;

      size_t num = min(numPrimitives/400,size_t(MAX_OPEN_SIZE));
      refs.reserve(num);

#if 1
      for (size_t i=0;i<refs.size();i++)
      {
        NodeRef ref = refs.back().node;
        if (ref.isAlignedNode())
          ref.prefetch();
      }
#endif

      std::make_heap(refs.begin(),refs.end());
      while (refs.size()+3 <= num)
      {
        std::pop_heap (refs.begin(),refs.end());
        NodeRef ref = refs.back().node;
        if (ref.isLeaf()) break;
        refs.pop_back();

        AlignedNode* node = ref.alignedNode();
        for (size_t i=0; i<N; i++) {
          if (node->child(i) == BVH::emptyNode) continue;
          refs.push_back(BuildRef(node->bounds(i),node->child(i)));

#if 1
          NodeRef ref_pre = node->child(i);
          if (ref_pre.isAlignedNode())
            ref_pre.prefetch();
#endif
          std::push_heap (refs.begin(),refs.end());
        }
      }
    }

#if defined(EMBREE_GEOMETRY_LINES)
    Builder* BVH4BuilderTwoLevelLineSegmentsSAH (void* bvh, Scene* scene, const createLineSegmentsAccelTy createMeshAccel) {
      return new BVHNBuilderTwoLevel<4,LineSegments>((BVH4*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(EMBREE_GEOMETRY_TRIANGLES)
    Builder* BVH4BuilderTwoLevelTriangleMeshSAH (void* bvh, Scene* scene, const createTriangleMeshAccelTy createMeshAccel) {
      return new BVHNBuilderTwoLevel<4,TriangleMesh>((BVH4*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(EMBREE_GEOMETRY_QUADS)
    Builder* BVH4BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, const createQuadMeshAccelTy createMeshAccel) {
    return new BVHNBuilderTwoLevel<4,QuadMesh>((BVH4*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(EMBREE_GEOMETRY_USER)
    Builder* BVH4BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, const createAccelSetAccelTy createMeshAccel) {
    return new BVHNBuilderTwoLevel<4,AccelSet>((BVH4*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(__AVX__)
#if defined(EMBREE_GEOMETRY_TRIANGLES)
    Builder* BVH8BuilderTwoLevelTriangleMeshSAH (void* bvh, Scene* scene, const createTriangleMeshAccelTy createMeshAccel) {
      return new BVHNBuilderTwoLevel<8,TriangleMesh>((BVH8*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(EMBREE_GEOMETRY_QUADS)
    Builder* BVH8BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, const createQuadMeshAccelTy createMeshAccel) {
      return new BVHNBuilderTwoLevel<8,QuadMesh>((BVH8*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(EMBREE_GEOMETRY_USER)
    Builder* BVH8BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, const createAccelSetAccelTy createMeshAccel) {
      return new BVHNBuilderTwoLevel<8,AccelSet>((BVH8*)bvh,scene,createMeshAccel);
    }
#endif
#endif
  }
}
<commit_msg>small fix in twolevel builder<commit_after>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "bvh_builder_twolevel.h"
#include "bvh_statistics.h"
#include "../builders/bvh_builder_sah.h"
#include "../common/scene_line_segments.h"
#include "../common/scene_triangle_mesh.h"
#include "../common/scene_quad_mesh.h"

#define PROFILE 0
#define MAX_OPEN_SIZE 10000
#define PROFILE_ITERATIONS 200

namespace embree
{
  namespace isa
  {
    template<int N, typename Mesh>
    BVHNBuilderTwoLevel<N,Mesh>::BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, const createMeshAccelTy createMeshAccel)
      : bvh(bvh), objects(bvh->objects), scene(scene), createMeshAccel(createMeshAccel), refs(scene->device), prims(scene->device) {}

    template<int N, typename Mesh>
    BVHNBuilderTwoLevel<N,Mesh>::~BVHNBuilderTwoLevel ()
    {
      for (size_t i=0; i<builders.size(); i++)
	delete builders[i];
    }

    template<int N, typename Mesh>
    void BVHNBuilderTwoLevel<N,Mesh>::build(size_t threadIndex, size_t threadCount)
    {
      /* delete some objects */
      size_t num = scene->size();
      if (num < objects.size()) {
        parallel_for(num, objects.size(), [&] (const range<size_t>& r) {
            for (size_t i=r.begin(); i<r.end(); i++) {
              delete builders[i]; builders[i] = nullptr;
              delete objects[i]; objects[i] = nullptr;
            }
          });
      }

      /* reset memory allocator */
      bvh->alloc.reset();

      /* skip build for empty scene */
      const size_t numPrimitives = scene->getNumPrimitives<Mesh,false>();
      if (numPrimitives == 0) {
        prims.resize(0);
        bvh->set(BVH::emptyNode,empty,0);
        return;
      }

      double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(N) + "BuilderTwoLevel");

#if PROFILE
	profile(2,PROFILE_ITERATIONS,numPrimitives,[&] (ProfileTimer& timer)
        {
#endif

      /* resize object array if scene got larger */
      if (objects.size()  < num) objects.resize(num);
      if (builders.size() < num) builders.resize(num);
      if (refs.size()     < num) refs.resize(num);
      nextRef.store(0);

      /* create of acceleration structures */
      parallel_for(size_t(0), num, [&] (const range<size_t>& r)
      {
        for (size_t objectID=r.begin(); objectID<r.end(); objectID++)
        {
          Mesh* mesh = scene->getSafe<Mesh>(objectID);

          /* verify meshes got deleted properly */
          if (mesh == nullptr || mesh->numTimeSteps != 1) {
            assert(objectID < objects.size () && objects[objectID] == nullptr);
            assert(objectID < builders.size() && builders[objectID] == nullptr);
            continue;
          }

          /* create BVH and builder for new meshes */
          if (objects[objectID] == nullptr)
            createMeshAccel(mesh,(AccelData*&)objects[objectID],builders[objectID]);
        }
      });

      /* parallel build of acceleration structures */
      parallel_for(size_t(0), num, [&] (const range<size_t>& r)
      {
        for (size_t objectID=r.begin(); objectID<r.end(); objectID++)
        {
          /* ignore if no triangle mesh or not enabled */
          Mesh* mesh = scene->getSafe<Mesh>(objectID);
          if (mesh == nullptr || !mesh->isEnabled() || mesh->numTimeSteps != 1)
            continue;

          BVH*     object  = objects [objectID]; assert(object);
          Builder* builder = builders[objectID]; assert(builder);

          /* build object if it got modified */
#if !PROFILE
          if (mesh->isModified())
#endif
            builder->build(0,0);

          /* create build primitive */
          if (!object->getBounds().empty())
            refs[nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root);
        }
      });

      /* fast path for single geometry scenes */
      if (nextRef == 1) {
        bvh->set(refs[0].node,LBBox3fa(refs[0].bounds()),numPrimitives);
      }

      else
      {
        /* open all large nodes */
        refs.resize(nextRef);
        open_sequential(numPrimitives);

        /* compute PrimRefs */
        prims.resize(refs.size());
        const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(),  PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo {

            PrimInfo pinfo(empty);
            for (size_t i=r.begin(); i<r.end(); i++) {
              pinfo.add(refs[i].bounds());
              prims[i] = PrimRef(refs[i].bounds(),(size_t)refs[i].node);
            }
            return pinfo;
          }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); });

        /* skip if all objects where empty */
        if (pinfo.size() == 0)
          bvh->set(BVH::emptyNode,empty,0);

        /* otherwise build toplevel hierarchy */
        else
        {
          NodeRef root;
          BVHBuilderBinnedSAH::build<NodeRef>
            (root,
             [&] { return bvh->alloc.threadLocal2(); },
             [&] (const isa::BVHBuilderBinnedSAH::BuildRecord& current, BVHBuilderBinnedSAH::BuildRecord* children, const size_t n, FastAllocator::ThreadLocal2* alloc) -> int
            {
              AlignedNode* node = (AlignedNode*) alloc->alloc0->malloc(sizeof(AlignedNode)); node->clear();
              for (size_t i=0; i<n; i++) {
                node->set(i,children[i].pinfo.geomBounds);
                children[i].parent = (size_t*)&node->child(i);
              }
              *current.parent = bvh->encodeNode(node);
              return 0;
            },
             [&] (const BVHBuilderBinnedSAH::BuildRecord& current, FastAllocator::ThreadLocal2* alloc) -> int
            {
              assert(current.prims.size() == 1);
              *current.parent = (NodeRef) prims[current.prims.begin()].ID();
              return 1;
            },
             [&] (size_t dn) { bvh->scene->progressMonitor(0); },
             prims.data(),pinfo,N,BVH::maxBuildDepthLeaf,N,1,1,1.0f,1.0f);

          bvh->set(root,LBBox3fa(pinfo.geomBounds),numPrimitives);
        }
      }

#if PROFILE
      });
#endif
      bvh->alloc.cleanup();
      bvh->postBuild(t0);
    }

    template<int N, typename Mesh>
    void BVHNBuilderTwoLevel<N,Mesh>::deleteGeometry(size_t geomID)
    {
      if (geomID >= objects.size()) return;
      delete builders[geomID]; builders[geomID] = nullptr;
      delete objects [geomID]; objects [geomID] = nullptr;
    }

    template<int N, typename Mesh>
    void BVHNBuilderTwoLevel<N,Mesh>::clear()
    {
      for (size_t i=0; i<objects.size(); i++)
        if (objects[i]) objects[i]->clear();

      for (size_t i=0; i<builders.size(); i++)
	if (builders[i]) builders[i]->clear();

      refs.clear();
    }

    template<int N, typename Mesh>
    void BVHNBuilderTwoLevel<N,Mesh>::open_sequential(size_t numPrimitives)
    {
      if (refs.size() == 0)
	return;

      size_t num = min(numPrimitives/400,size_t(MAX_OPEN_SIZE));
      refs.reserve(num);

#if 1
      for (size_t i=0;i<refs.size();i++)
      {
        NodeRef ref = refs.back().node;
        if (ref.isAlignedNode())
          ref.prefetch();
      }
#endif

      std::make_heap(refs.begin(),refs.end());
      while (refs.size()+3 <= num)
      {
        std::pop_heap (refs.begin(),refs.end());
        NodeRef ref = refs.back().node;
        if (ref.isLeaf()) break;
        refs.pop_back();

        AlignedNode* node = ref.alignedNode();
        for (size_t i=0; i<N; i++) {
          if (node->child(i) == BVH::emptyNode) continue;
          refs.push_back(BuildRef(node->bounds(i),node->child(i)));

#if 1
          NodeRef ref_pre = node->child(i);
          if (ref_pre.isAlignedNode())
            ref_pre.prefetch();
#endif
          std::push_heap (refs.begin(),refs.end());
        }
      }
    }

#if defined(EMBREE_GEOMETRY_LINES)
    Builder* BVH4BuilderTwoLevelLineSegmentsSAH (void* bvh, Scene* scene, const createLineSegmentsAccelTy createMeshAccel) {
      return new BVHNBuilderTwoLevel<4,LineSegments>((BVH4*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(EMBREE_GEOMETRY_TRIANGLES)
    Builder* BVH4BuilderTwoLevelTriangleMeshSAH (void* bvh, Scene* scene, const createTriangleMeshAccelTy createMeshAccel) {
      return new BVHNBuilderTwoLevel<4,TriangleMesh>((BVH4*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(EMBREE_GEOMETRY_QUADS)
    Builder* BVH4BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, const createQuadMeshAccelTy createMeshAccel) {
    return new BVHNBuilderTwoLevel<4,QuadMesh>((BVH4*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(EMBREE_GEOMETRY_USER)
    Builder* BVH4BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, const createAccelSetAccelTy createMeshAccel) {
    return new BVHNBuilderTwoLevel<4,AccelSet>((BVH4*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(__AVX__)
#if defined(EMBREE_GEOMETRY_TRIANGLES)
    Builder* BVH8BuilderTwoLevelTriangleMeshSAH (void* bvh, Scene* scene, const createTriangleMeshAccelTy createMeshAccel) {
      return new BVHNBuilderTwoLevel<8,TriangleMesh>((BVH8*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(EMBREE_GEOMETRY_QUADS)
    Builder* BVH8BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, const createQuadMeshAccelTy createMeshAccel) {
      return new BVHNBuilderTwoLevel<8,QuadMesh>((BVH8*)bvh,scene,createMeshAccel);
    }
#endif

#if defined(EMBREE_GEOMETRY_USER)
    Builder* BVH8BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, const createAccelSetAccelTy createMeshAccel) {
      return new BVHNBuilderTwoLevel<8,AccelSet>((BVH8*)bvh,scene,createMeshAccel);
    }
#endif
#endif
  }
}
<|endoftext|>


<commit_before>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2016 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program 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 Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include "Backup.h"
#include "server_settings.h"
#include "../Interface/Server.h"
#include "database.h"
#include "../urbackupcommon/os_functions.h"
#include "server_log.h"
#include "../stringtools.h"
#include "ClientMain.h"
#include "../urlplugin/IUrlFactory.h"
#include "server_status.h"
#include "server_cleanup.h"

extern IUrlFactory *url_fak;

namespace
{
	class DelayedWakeup : public IThread
	{
	public:
		DelayedWakeup(ClientMain* client_main)
			: client_main(client_main)
		{

		}

		void operator()()
		{
			Server->wait(1000);
			client_main->getInternalCommandPipe()->Write("WAKEUP");
			delete this;
		}

	private:
		ClientMain* client_main;
	};
}

Backup::Backup(ClientMain* client_main, int clientid, std::string clientname, std::string clientsubname,
	LogAction log_action, bool is_file_backup, bool is_incremental, std::string server_token, std::string details, bool scheduled)
	: client_main(client_main), clientid(clientid), clientname(clientname), clientsubname(clientsubname), log_action(log_action),
	is_file_backup(is_file_backup), r_incremental(is_incremental), r_resumed(false), backup_result(false),
	log_backup(true), has_early_error(false), should_backoff(true), db(NULL), status_id(0), has_timeout_error(false),
	server_token(server_token), details(details), num_issues(0), stop_backup_running(true), scheduled(scheduled)
{

}

void Backup::operator()()
{
	logid = ServerLogger::getLogId(clientid);
	db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);
	server_settings.reset(new ServerSettings(db, clientid));
	ScopedFreeObjRef<ServerBackupDao*> backup_dao_free(backup_dao);
	backup_dao = new ServerBackupDao(db);

	ScopedActiveThread sat;
	active_thread=sat.get();

	if(is_file_backup)
	{
		if(r_incremental)
		{
			if(r_resumed)
			{
				status_id = ServerStatus::startProcess(clientname, sa_resume_incr_file, details, logid, true);
			}
			else
			{
				status_id = ServerStatus::startProcess(clientname, sa_incr_file, details, logid, true);
			}
		}
		else
		{
			if(r_resumed)
			{
				status_id = ServerStatus::startProcess(clientname, sa_resume_full_file, details, logid, true);
			}
			else
			{
				status_id = ServerStatus::startProcess(clientname, sa_full_file, details, logid, true);
			}
		}
	}
	else
	{
		if(r_incremental)
		{
			status_id = ServerStatus::startProcess(clientname, sa_incr_image, details, logid, true);
		}
		else
		{
			status_id = ServerStatus::startProcess(clientname, sa_full_image, details, logid, true);
		}
		ServerStatus::setProcessPcDone(clientname, status_id, 0);
	}

	createDirectoryForClient();

	int64 backup_starttime=Server->getTimeMS();

	bool do_log = false;
	backup_result = doBackup();

	if (stop_backup_running)
	{
		client_main->stopBackupRunning(is_file_backup);
	}

	if(!has_early_error && log_action!=LogAction_NoLogging)
	{
		ServerLogger::Log(logid, "Time taken for backing up client "+clientname+": "+PrettyPrintTime(Server->getTimeMS()-backup_starttime), LL_INFO);
		if(!backup_result)
		{
			ServerLogger::Log(logid, "Backup failed", LL_ERROR);
		}
		else if(num_issues==0)
		{
			ServerLogger::Log(logid, "Backup succeeded", LL_INFO);
		}
		else
		{
			ServerLogger::Log(logid, "Backup completed with issues", LL_INFO);
		}
	}

	if (!has_early_error)
	{
		ServerCleanupThread::updateStats(false);
	}

	if( (log_backup || log_action == LogAction_AlwaysLog) && log_action!=LogAction_NoLogging)
	{
		saveClientLogdata(is_file_backup?0:1, r_incremental?1:0, backup_result && !has_early_error, r_resumed);
	}

	ServerLogger::reset(logid);
	ServerStatus::stopProcess(clientname, status_id);

	server_settings.reset();
	db=NULL;

	Server->getThreadPool()->execute(new DelayedWakeup(client_main));
}

void Backup::setErrors(Backup& other)
{
	should_backoff = other->shouldBackoff();
	has_timeout_error = other->hasTimeoutError();
}

bool Backup::createDirectoryForClient(void)
{
	std::string backupfolder=server_settings->getSettings()->backupfolder;
	if(!os_create_dir(os_file_prefix(backupfolder+os_file_sep()+clientname)) && !os_directory_exists(os_file_prefix(backupfolder+os_file_sep()+clientname)) )
	{
		Server->Log("Could not create or read directory for client \""+clientname+"\"", LL_ERROR);
		return false;
	}
	return true;
}

void Backup::saveClientLogdata(int image, int incremental, bool r_success, bool resumed)
{
	int errors=0;
	int warnings=0;
	int infos=0;
	std::string logdata=ServerLogger::getLogdata(logid, errors, warnings, infos);

	backup_dao->saveBackupLog(clientid, errors, warnings, infos, is_file_backup?0:1,
		r_incremental?1:0, r_resumed?1:0, 0);

	backup_dao->saveBackupLogData(db->getLastInsertID(), logdata);

	sendLogdataMail(r_success, image, incremental, resumed, errors, warnings, infos, logdata);
}

void Backup::sendLogdataMail(bool r_success, int image, int incremental, bool resumed, int errors, int warnings, int infos, std::string &data)
{
	MailServer mail_server=ClientMain::getMailServerSettings();
	if(mail_server.servername.empty())
		return;

	if(url_fak==NULL)
		return;

	std::vector<int> mailable_user_ids = backup_dao->getMailableUserIds();
	for(size_t i=0;i<mailable_user_ids.size();++i)
	{
		std::string logr=getUserRights(mailable_user_ids[i], "logs");
		bool has_r=false;
		if(logr!="all")
		{
			std::vector<std::string> toks;
			Tokenize(logr, toks, ",");
			for(size_t j=0;j<toks.size();++j)
			{
				if(watoi(toks[j])==clientid)
				{
					has_r=true;
				}
			}
		}
		else
		{
			has_r=true;
		}

		if(has_r)
		{
			ServerBackupDao::SReportSettings report_settings =
				backup_dao->getUserReportSettings(mailable_user_ids[i]);

			if(report_settings.exists)
			{
				std::string report_mail=report_settings.report_mail;
				int report_loglevel=report_settings.report_loglevel;
				int report_sendonly=report_settings.report_sendonly;

				if( ( ( report_loglevel==0 && infos>0 )
					|| ( report_loglevel<=1 && warnings>0 )
					|| ( report_loglevel<=2 && errors>0 ) ) &&
					(report_sendonly==0 ||
					( report_sendonly==1 && !r_success ) ||
					( report_sendonly==2 && r_success) ||
					( report_sendonly==3 && !r_success && !has_timeout_error) ) )
				{
					std::vector<std::string> to_addrs;
					Tokenize(report_mail, to_addrs, ",;");

					std::string subj="UrBackup: ";
					std::string msg="UrBackup just did ";
					if(incremental>0)
					{
						if(resumed)
						{
							msg+="a resumed incremental ";
							subj+="Resumed incremental ";
						}
						else
						{
							msg+="an incremental ";
							subj+="Incremental ";
						}
					}
					else
					{
						if(resumed)
						{
							msg+="a resumed full ";
							subj+="Resumed full ";
						}
						else
						{
							msg+="a full ";
							subj+="Full ";
						}
					}

					if(image>0)
					{
						msg+="image ";
						subj+="image ";
					}
					else
					{
						msg+="file ";
						subj+="file ";
					}
					subj+="backup of \""+clientname+"\"\n";
					msg+="backup of \""+clientname+"\".\n";
					msg+="\nReport:\n";
					msg+="( "+convert(infos);
					if(infos!=1) msg+=" infos, ";
					else msg+=" info, ";
					msg+=convert(warnings);
					if(warnings!=1) msg+=" warnings, ";
					else msg+=" warning, ";
					msg+=convert(errors);
					if(errors!=1) msg+=" errors";
					else msg+=" error";
					msg+=" )\n\n";
					std::vector<std::string> msgs;
					TokenizeMail(data, msgs, "\n");

					for(size_t j=0;j<msgs.size();++j)
					{
						std::string ll;
						if(!msgs[j].empty()) ll=msgs[j][0];
						int li=watoi(ll);
						msgs[j].erase(0, 2);
						std::string tt=getuntil("-", msgs[j]);
						std::string m=getafter("-", msgs[j]);
						tt=backup_dao->formatUnixtime(watoi64(tt)).value;
						std::string lls="info";
						if(li==1) lls="warning";
						else if(li==2) lls="error";
						msg+=(tt)+"("+lls+"): "+(m)+"\n";
					}
					if(!r_success)
						subj+=" - failed";
					else
						subj+=" - success";

					std::string errmsg;
					bool b=url_fak->sendMail(mail_server, to_addrs, subj, msg, &errmsg);
					if(!b)
					{
						Server->Log("Sending mail failed. "+errmsg, LL_WARNING);
					}
				}
			}
		}
	}
}

std::string Backup::getUserRights(int userid, std::string domain)
{
	if(domain!="all")
	{
		if(getUserRights(userid, "all")=="all")
			return "all";
	}

	ServerBackupDao::CondString t_right = backup_dao->getUserRight(userid, domain);
	if(t_right.exists)
	{
		return t_right.value;
	}
	else
	{
		return "none";
	}
}
<commit_msg>Set shouldBackoff and hasTimeoutError after SYSVOL/ESP backup fails<commit_after>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2016 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program 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 Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include "Backup.h"
#include "server_settings.h"
#include "../Interface/Server.h"
#include "database.h"
#include "../urbackupcommon/os_functions.h"
#include "server_log.h"
#include "../stringtools.h"
#include "ClientMain.h"
#include "../urlplugin/IUrlFactory.h"
#include "server_status.h"
#include "server_cleanup.h"

extern IUrlFactory *url_fak;

namespace
{
	class DelayedWakeup : public IThread
	{
	public:
		DelayedWakeup(ClientMain* client_main)
			: client_main(client_main)
		{

		}

		void operator()()
		{
			Server->wait(1000);
			client_main->getInternalCommandPipe()->Write("WAKEUP");
			delete this;
		}

	private:
		ClientMain* client_main;
	};
}

Backup::Backup(ClientMain* client_main, int clientid, std::string clientname, std::string clientsubname,
	LogAction log_action, bool is_file_backup, bool is_incremental, std::string server_token, std::string details, bool scheduled)
	: client_main(client_main), clientid(clientid), clientname(clientname), clientsubname(clientsubname), log_action(log_action),
	is_file_backup(is_file_backup), r_incremental(is_incremental), r_resumed(false), backup_result(false),
	log_backup(true), has_early_error(false), should_backoff(true), db(NULL), status_id(0), has_timeout_error(false),
	server_token(server_token), details(details), num_issues(0), stop_backup_running(true), scheduled(scheduled)
{

}

void Backup::operator()()
{
	logid = ServerLogger::getLogId(clientid);
	db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);
	server_settings.reset(new ServerSettings(db, clientid));
	ScopedFreeObjRef<ServerBackupDao*> backup_dao_free(backup_dao);
	backup_dao = new ServerBackupDao(db);

	ScopedActiveThread sat;
	active_thread=sat.get();

	if(is_file_backup)
	{
		if(r_incremental)
		{
			if(r_resumed)
			{
				status_id = ServerStatus::startProcess(clientname, sa_resume_incr_file, details, logid, true);
			}
			else
			{
				status_id = ServerStatus::startProcess(clientname, sa_incr_file, details, logid, true);
			}
		}
		else
		{
			if(r_resumed)
			{
				status_id = ServerStatus::startProcess(clientname, sa_resume_full_file, details, logid, true);
			}
			else
			{
				status_id = ServerStatus::startProcess(clientname, sa_full_file, details, logid, true);
			}
		}
	}
	else
	{
		if(r_incremental)
		{
			status_id = ServerStatus::startProcess(clientname, sa_incr_image, details, logid, true);
		}
		else
		{
			status_id = ServerStatus::startProcess(clientname, sa_full_image, details, logid, true);
		}
		ServerStatus::setProcessPcDone(clientname, status_id, 0);
	}

	createDirectoryForClient();

	int64 backup_starttime=Server->getTimeMS();

	bool do_log = false;
	backup_result = doBackup();

	if (stop_backup_running)
	{
		client_main->stopBackupRunning(is_file_backup);
	}

	if(!has_early_error && log_action!=LogAction_NoLogging)
	{
		ServerLogger::Log(logid, "Time taken for backing up client "+clientname+": "+PrettyPrintTime(Server->getTimeMS()-backup_starttime), LL_INFO);
		if(!backup_result)
		{
			ServerLogger::Log(logid, "Backup failed", LL_ERROR);
		}
		else if(num_issues==0)
		{
			ServerLogger::Log(logid, "Backup succeeded", LL_INFO);
		}
		else
		{
			ServerLogger::Log(logid, "Backup completed with issues", LL_INFO);
		}
	}

	if (!has_early_error)
	{
		ServerCleanupThread::updateStats(false);
	}

	if( (log_backup || log_action == LogAction_AlwaysLog) && log_action!=LogAction_NoLogging)
	{
		saveClientLogdata(is_file_backup?0:1, r_incremental?1:0, backup_result && !has_early_error, r_resumed);
	}

	ServerLogger::reset(logid);
	ServerStatus::stopProcess(clientname, status_id);

	server_settings.reset();
	db=NULL;

	Server->getThreadPool()->execute(new DelayedWakeup(client_main));
}

void Backup::setErrors(Backup& other)
{
	should_backoff = other.shouldBackoff();
	has_timeout_error = other.hasTimeoutError();
}

bool Backup::createDirectoryForClient(void)
{
	std::string backupfolder=server_settings->getSettings()->backupfolder;
	if(!os_create_dir(os_file_prefix(backupfolder+os_file_sep()+clientname)) && !os_directory_exists(os_file_prefix(backupfolder+os_file_sep()+clientname)) )
	{
		Server->Log("Could not create or read directory for client \""+clientname+"\"", LL_ERROR);
		return false;
	}
	return true;
}

void Backup::saveClientLogdata(int image, int incremental, bool r_success, bool resumed)
{
	int errors=0;
	int warnings=0;
	int infos=0;
	std::string logdata=ServerLogger::getLogdata(logid, errors, warnings, infos);

	backup_dao->saveBackupLog(clientid, errors, warnings, infos, is_file_backup?0:1,
		r_incremental?1:0, r_resumed?1:0, 0);

	backup_dao->saveBackupLogData(db->getLastInsertID(), logdata);

	sendLogdataMail(r_success, image, incremental, resumed, errors, warnings, infos, logdata);
}

void Backup::sendLogdataMail(bool r_success, int image, int incremental, bool resumed, int errors, int warnings, int infos, std::string &data)
{
	MailServer mail_server=ClientMain::getMailServerSettings();
	if(mail_server.servername.empty())
		return;

	if(url_fak==NULL)
		return;

	std::vector<int> mailable_user_ids = backup_dao->getMailableUserIds();
	for(size_t i=0;i<mailable_user_ids.size();++i)
	{
		std::string logr=getUserRights(mailable_user_ids[i], "logs");
		bool has_r=false;
		if(logr!="all")
		{
			std::vector<std::string> toks;
			Tokenize(logr, toks, ",");
			for(size_t j=0;j<toks.size();++j)
			{
				if(watoi(toks[j])==clientid)
				{
					has_r=true;
				}
			}
		}
		else
		{
			has_r=true;
		}

		if(has_r)
		{
			ServerBackupDao::SReportSettings report_settings =
				backup_dao->getUserReportSettings(mailable_user_ids[i]);

			if(report_settings.exists)
			{
				std::string report_mail=report_settings.report_mail;
				int report_loglevel=report_settings.report_loglevel;
				int report_sendonly=report_settings.report_sendonly;

				if( ( ( report_loglevel==0 && infos>0 )
					|| ( report_loglevel<=1 && warnings>0 )
					|| ( report_loglevel<=2 && errors>0 ) ) &&
					(report_sendonly==0 ||
					( report_sendonly==1 && !r_success ) ||
					( report_sendonly==2 && r_success) ||
					( report_sendonly==3 && !r_success && !has_timeout_error) ) )
				{
					std::vector<std::string> to_addrs;
					Tokenize(report_mail, to_addrs, ",;");

					std::string subj="UrBackup: ";
					std::string msg="UrBackup just did ";
					if(incremental>0)
					{
						if(resumed)
						{
							msg+="a resumed incremental ";
							subj+="Resumed incremental ";
						}
						else
						{
							msg+="an incremental ";
							subj+="Incremental ";
						}
					}
					else
					{
						if(resumed)
						{
							msg+="a resumed full ";
							subj+="Resumed full ";
						}
						else
						{
							msg+="a full ";
							subj+="Full ";
						}
					}

					if(image>0)
					{
						msg+="image ";
						subj+="image ";
					}
					else
					{
						msg+="file ";
						subj+="file ";
					}
					subj+="backup of \""+clientname+"\"\n";
					msg+="backup of \""+clientname+"\".\n";
					msg+="\nReport:\n";
					msg+="( "+convert(infos);
					if(infos!=1) msg+=" infos, ";
					else msg+=" info, ";
					msg+=convert(warnings);
					if(warnings!=1) msg+=" warnings, ";
					else msg+=" warning, ";
					msg+=convert(errors);
					if(errors!=1) msg+=" errors";
					else msg+=" error";
					msg+=" )\n\n";
					std::vector<std::string> msgs;
					TokenizeMail(data, msgs, "\n");

					for(size_t j=0;j<msgs.size();++j)
					{
						std::string ll;
						if(!msgs[j].empty()) ll=msgs[j][0];
						int li=watoi(ll);
						msgs[j].erase(0, 2);
						std::string tt=getuntil("-", msgs[j]);
						std::string m=getafter("-", msgs[j]);
						tt=backup_dao->formatUnixtime(watoi64(tt)).value;
						std::string lls="info";
						if(li==1) lls="warning";
						else if(li==2) lls="error";
						msg+=(tt)+"("+lls+"): "+(m)+"\n";
					}
					if(!r_success)
						subj+=" - failed";
					else
						subj+=" - success";

					std::string errmsg;
					bool b=url_fak->sendMail(mail_server, to_addrs, subj, msg, &errmsg);
					if(!b)
					{
						Server->Log("Sending mail failed. "+errmsg, LL_WARNING);
					}
				}
			}
		}
	}
}

std::string Backup::getUserRights(int userid, std::string domain)
{
	if(domain!="all")
	{
		if(getUserRights(userid, "all")=="all")
			return "all";
	}

	ServerBackupDao::CondString t_right = backup_dao->getUserRight(userid, domain);
	if(t_right.exists)
	{
		return t_right.value;
	}
	else
	{
		return "none";
	}
}
<|endoftext|>


<commit_before>//_________________________________________________________________________
//  Utility Class for transverse energy studies
//  Base class for ESD & MC analysis
//  - cuts for reconstruction and MonteCarlo
// implementation file
//
//*-- Authors: Oystein Djuvsland (Bergen), David Silvermyr (ORNL)
//_________________________________________________________________________

#include "AliAnalysisEtCuts.h"

#include <iostream>
#include "TNamed.h"

using namespace std;

ClassImp(AliAnalysisEtCuts);

AliAnalysisEtCuts::AliAnalysisEtCuts() :
  TNamed()
				    //
  ,fCommonEtaCut(0.5)
  ,fCommonClusterEnergyCut(0.15)
  ,fCommonTrackPtCut(0.0)
  ,fCommonSingleCell(1)
  ,fEmcalTrackDistanceCut(15.0)
  ,fEmcalTrackDxCut(5.0)
  ,fEmcalTrackDzCut(5.0)
  ,fPhosTrackDistanceCut(10.0)
  ,fPhosTrackDxCut(8.0)
  ,fPhosTrackDzCut(3.0)
  ,fPhosTrackRCut(5.0)
  ,fPhosBadDistanceCut(3.0)

  ,fGeometryPhosEtaAccCut(0.12)
  ,fGeometryPhosPhiAccMinCut(260.0)
  ,fGeometryPhosPhiAccMaxCut(320.0)
  ,fGeometryPhosDetectorRadius(460.0)
				    //
  ,fGeometryEmcalEtaAccCut(0.7)
  ,fGeometryEmcalPhiAccMinCut(80.0) // rad 1.4
  ,fGeometryEmcalPhiAccMaxCut(120.0) // rad 2.1
  ,fGeometryEmcalDetectorRadius(440.0)
				    //
  ,fReconstructedVertexXCut(0.5)
  ,fReconstructedVertexYCut(0.5)
  ,fReconstructedVertexZCut(12.0)
  ,fReconstructedIPxyCut(1.5)
  ,fReconstructedIPzCut(1.5)
  ,fReconstructedNTpcClustersCut(30)
  ,fReconstructedNItsClustersCut(3)
  ,fReconstructedPidCut(0.0)
				    //
  ,fReconstructedPhosClusterType(-1)
  ,fReconstructedPhosClusterEnergyCut(0.25)
  ,fReconstructedPhosSingleCellEnergyCut(0.5)
  ,fReconstructedPhosTrackDistanceTightCut(3.0)
  ,fReconstructedPhosTrackDistanceMediumCut(5.0)
  ,fReconstructedPhosTrackDistanceLooseCut(15.0)
				    //
  ,fReconstructedEmcalClusterType(1)
  ,fReconstructedEmcalClusterEnergyCut(0.3) // GeV
  ,fReconstructedEmcalSingleCellEnergyCut(0.5)
  ,fReconstructedEmcalTrackDistanceTightCut(5.0)
  ,fReconstructedEmcalTrackDistanceMediumCut(10.0)
  ,fReconstructedEmcalTrackDistanceLooseCut(15.0)

  ,fMonteCarloSingleChargedParticle(3)
  ,fMonteCarloNeutralParticle(0)

  ,fHistMakeTree(kTRUE)
  ,fHistMakeTreeDeposit(kFALSE)
  ,fHistNbinsMult(2000)
  ,fHistMinMult(-0.5)
  ,fHistMaxMult(1999.5)
  ,fHistNbinsTotEt(10000)
  ,fHistMinTotEt(0.000)
  ,fHistMaxTotEt(1000)
  ,fHistNbinsParticleEt(5000)
  ,fHistMinParticleEt(0)
  ,fHistMaxParticleEt(500)
  ,fHistNbinsParticlePt(200)
  ,fHistMinParticlePt(0)
  ,fHistMaxParticlePt(20)

  ,fPrimaryVertexCutXY(4.0)
  ,fPrimaryVertexCutZ(20.0)
{ // ctor
}

AliAnalysisEtCuts::~AliAnalysisEtCuts()
{ // dtor
}

void AliAnalysisEtCuts::SetPbPbDefaults()
{ // just increase seom histogram max values for now
  // enough to multiply conservative p+p defaults by a factor 100?
  fHistMaxMult = 20000;
  fHistMaxTotEt = 10000;
}

<commit_msg>Changing eta cut for the EMCal since we arent getting clusters on the edges anyways<commit_after>//_________________________________________________________________________
//  Utility Class for transverse energy studies
//  Base class for ESD & MC analysis
//  - cuts for reconstruction and MonteCarlo
// implementation file
//
//*-- Authors: Oystein Djuvsland (Bergen), David Silvermyr (ORNL)
//_________________________________________________________________________

#include "AliAnalysisEtCuts.h"

#include <iostream>
#include "TNamed.h"

using namespace std;

ClassImp(AliAnalysisEtCuts);

AliAnalysisEtCuts::AliAnalysisEtCuts() :
  TNamed()
				    //
  ,fCommonEtaCut(0.5)
  ,fCommonClusterEnergyCut(0.15)
  ,fCommonTrackPtCut(0.0)
  ,fCommonSingleCell(1)
  ,fEmcalTrackDistanceCut(15.0)
  ,fEmcalTrackDxCut(5.0)
  ,fEmcalTrackDzCut(5.0)
  ,fPhosTrackDistanceCut(10.0)
  ,fPhosTrackDxCut(8.0)
  ,fPhosTrackDzCut(3.0)
  ,fPhosTrackRCut(5.0)
  ,fPhosBadDistanceCut(3.0)

  ,fGeometryPhosEtaAccCut(0.12)
  ,fGeometryPhosPhiAccMinCut(260.0)
  ,fGeometryPhosPhiAccMaxCut(320.0)
  ,fGeometryPhosDetectorRadius(460.0)
				    //
  ,fGeometryEmcalEtaAccCut(0.6)
  ,fGeometryEmcalPhiAccMinCut(80.0) // rad 1.4
  ,fGeometryEmcalPhiAccMaxCut(120.0) // rad 2.1
  ,fGeometryEmcalDetectorRadius(440.0)
				    //
  ,fReconstructedVertexXCut(0.5)
  ,fReconstructedVertexYCut(0.5)
  ,fReconstructedVertexZCut(12.0)
  ,fReconstructedIPxyCut(1.5)
  ,fReconstructedIPzCut(1.5)
  ,fReconstructedNTpcClustersCut(30)
  ,fReconstructedNItsClustersCut(3)
  ,fReconstructedPidCut(0.0)
				    //
  ,fReconstructedPhosClusterType(-1)
  ,fReconstructedPhosClusterEnergyCut(0.25)
  ,fReconstructedPhosSingleCellEnergyCut(0.5)
  ,fReconstructedPhosTrackDistanceTightCut(3.0)
  ,fReconstructedPhosTrackDistanceMediumCut(5.0)
  ,fReconstructedPhosTrackDistanceLooseCut(15.0)
				    //
  ,fReconstructedEmcalClusterType(1)
  ,fReconstructedEmcalClusterEnergyCut(0.3) // GeV
  ,fReconstructedEmcalSingleCellEnergyCut(0.5)
  ,fReconstructedEmcalTrackDistanceTightCut(5.0)
  ,fReconstructedEmcalTrackDistanceMediumCut(10.0)
  ,fReconstructedEmcalTrackDistanceLooseCut(15.0)

  ,fMonteCarloSingleChargedParticle(3)
  ,fMonteCarloNeutralParticle(0)

  ,fHistMakeTree(kTRUE)
  ,fHistMakeTreeDeposit(kFALSE)
  ,fHistNbinsMult(2000)
  ,fHistMinMult(-0.5)
  ,fHistMaxMult(1999.5)
  ,fHistNbinsTotEt(10000)
  ,fHistMinTotEt(0.000)
  ,fHistMaxTotEt(1000)
  ,fHistNbinsParticleEt(5000)
  ,fHistMinParticleEt(0)
  ,fHistMaxParticleEt(500)
  ,fHistNbinsParticlePt(200)
  ,fHistMinParticlePt(0)
  ,fHistMaxParticlePt(20)

  ,fPrimaryVertexCutXY(4.0)
  ,fPrimaryVertexCutZ(20.0)
{ // ctor
}

AliAnalysisEtCuts::~AliAnalysisEtCuts()
{ // dtor
}

void AliAnalysisEtCuts::SetPbPbDefaults()
{ // just increase seom histogram max values for now
  // enough to multiply conservative p+p defaults by a factor 100?
  fHistMaxMult = 20000;
  fHistMaxTotEt = 10000;
}

<|endoftext|>


<commit_before>/* mbed Microcontroller Library - stackheap
 * Copyright (C) 2009-2011 ARM Limited. All rights reserved.
 *
 * Setup a fixed single stack/heap memory model,
 *  between the top of the RW/ZI region and the stackpointer
 */

#ifdef __cplusplus
extern "C" {
#endif

#include <sys/types.h>
#include <errno.h>

extern void exit(int return_code);

int _kill(int pid, int sig) {
    errno = EINVAL;
    return -1;
}

void _exit(int status) {
  exit(status);
}

int _getpid(void) {
  return 1;
}

#ifdef __cplusplus
}
#endif
<commit_msg>Fix KL43Z GCC_ARM build<commit_after><|endoftext|>