70#define DEBUG_TYPE "on-disk-cas"
88 return ID.takeError();
91 "corrupt object '" +
toHex(*
ID) +
"'");
101 enum class StorageKind : uint8_t {
118 StandaloneLeaf0 = 12,
121 static StringRef getStandaloneFilePrefix(StorageKind SK) {
125 case TrieRecord::StorageKind::Standalone:
127 case TrieRecord::StorageKind::StandaloneLeaf:
129 case TrieRecord::StorageKind::StandaloneLeaf0:
134 enum Limits : int64_t {
136 MaxEmbeddedSize = 64LL * 1024LL - 1,
140 StorageKind SK = StorageKind::Unknown;
145 static uint64_t pack(Data
D) {
146 assert(
D.Offset.get() < (int64_t)(1ULL << 56));
147 uint64_t
Packed = uint64_t(
D.SK) << 56 |
D.Offset.get();
148 assert(
D.SK != StorageKind::Unknown || Packed == 0);
150 Data RoundTrip = unpack(Packed);
152 assert(
D.Offset.get() == RoundTrip.Offset.get());
158 static Data unpack(uint64_t Packed) {
162 D.SK = (StorageKind)(Packed >> 56);
167 TrieRecord() : Storage(0) {}
169 Data
load()
const {
return unpack(Storage); }
170 bool compare_exchange_strong(Data &Existing, Data New);
173 std::atomic<uint64_t> Storage;
183struct DataRecordHandle {
186 enum class NumRefsFlags : uint8_t {
196 enum class DataSizeFlags {
205 enum class RefKindFlags {
214 DataSizeShift = NumRefsShift + NumRefsBits,
216 RefKindShift = DataSizeShift + DataSizeBits,
219 static_assert(((UINT32_MAX << NumRefsBits) & (uint32_t)NumRefsFlags::Max) ==
222 static_assert(((UINT32_MAX << DataSizeBits) & (uint32_t)DataSizeFlags::Max) ==
225 static_assert(((UINT32_MAX << RefKindBits) & (uint32_t)RefKindFlags::Max) ==
231 NumRefsFlags NumRefs;
232 DataSizeFlags DataSize;
233 RefKindFlags RefKind;
235 static uint64_t pack(LayoutFlags LF) {
236 unsigned Packed = ((unsigned)LF.NumRefs << NumRefsShift) |
237 ((
unsigned)LF.DataSize << DataSizeShift) |
238 ((unsigned)LF.RefKind << RefKindShift);
240 LayoutFlags RoundTrip = unpack(Packed);
241 assert(LF.NumRefs == RoundTrip.NumRefs);
242 assert(LF.DataSize == RoundTrip.DataSize);
243 assert(LF.RefKind == RoundTrip.RefKind);
247 static LayoutFlags unpack(uint64_t Storage) {
248 assert(Storage <= UINT8_MAX &&
"Expect storage to fit in a byte");
251 (NumRefsFlags)((Storage >> NumRefsShift) & ((1U << NumRefsBits) - 1));
252 LF.DataSize = (DataSizeFlags)((Storage >> DataSizeShift) &
253 ((1U << DataSizeBits) - 1));
255 (RefKindFlags)((Storage >> RefKindShift) & ((1U << RefKindBits) - 1));
265 using PackTy = uint32_t;
268 static constexpr unsigned LayoutFlagsShift =
269 (
sizeof(PackTy) - 1) * CHAR_BIT;
273 InternalRefArrayRef Refs;
277 LayoutFlags getLayoutFlags()
const {
278 return LayoutFlags::unpack(H->Packed >> Header::LayoutFlagsShift);
282 void skipDataSize(LayoutFlags LF, int64_t &RelOffset)
const;
283 uint32_t getNumRefs()
const;
284 void skipNumRefs(LayoutFlags LF, int64_t &RelOffset)
const;
285 int64_t getRefsRelOffset()
const;
286 int64_t getDataRelOffset()
const;
288 static uint64_t getTotalSize(uint64_t DataRelOffset, uint64_t
DataSize) {
289 return DataRelOffset +
DataSize + 1;
291 uint64_t getTotalSize()
const {
298 explicit Layout(
const Input &
I);
301 uint64_t DataSize = 0;
302 uint32_t NumRefs = 0;
303 int64_t RefsRelOffset = 0;
304 int64_t DataRelOffset = 0;
305 uint64_t getTotalSize()
const {
306 return DataRecordHandle::getTotalSize(DataRelOffset, DataSize);
310 InternalRefArrayRef getRefs()
const {
311 assert(H &&
"Expected valid handle");
312 auto *BeginByte =
reinterpret_cast<const char *
>(H) + getRefsRelOffset();
313 size_t Size = getNumRefs();
315 return InternalRefArrayRef();
316 if (getLayoutFlags().RefKind == RefKindFlags::InternalRef4B)
317 return ArrayRef(
reinterpret_cast<const InternalRef4B *
>(BeginByte),
Size);
318 return ArrayRef(
reinterpret_cast<const InternalRef *
>(BeginByte),
Size);
321 ArrayRef<char> getData()
const {
322 assert(H &&
"Expected valid handle");
323 return ArrayRef(
reinterpret_cast<const char *
>(H) + getDataRelOffset(),
327 static DataRecordHandle create(function_ref<
char *(
size_t Size)>
Alloc,
329 static Expected<DataRecordHandle>
330 createWithError(function_ref<Expected<char *>(
size_t Size)>
Alloc,
332 static DataRecordHandle construct(
char *Mem,
const Input &
I);
334 static DataRecordHandle
get(
const char *Mem) {
335 return DataRecordHandle(
336 *
reinterpret_cast<const DataRecordHandle::Header *
>(Mem));
338 static Expected<DataRecordHandle>
339 getFromDataPool(
const OnDiskDataAllocator &Pool, FileOffset
Offset);
341 explicit operator bool()
const {
return H; }
342 const Header &getHeader()
const {
return *H; }
344 DataRecordHandle() =
default;
345 explicit DataRecordHandle(
const Header &H) : H(&H) {}
348 static DataRecordHandle constructImpl(
char *Mem,
const Input &
I,
350 const Header *H =
nullptr;
354struct OnDiskContent {
355 std::optional<DataRecordHandle> Record;
356 std::optional<ArrayRef<char>> Bytes;
358 ArrayRef<char> getData()
const {
361 assert(Record &&
"Expected record or bytes");
362 return Record->getData();
367class StandaloneDataInMemory {
369 OnDiskContent getContent()
const;
371 OnDiskGraphDB::FileBackedData
372 getInternalFileBackedObjectData(StringRef RootPath)
const;
374 StandaloneDataInMemory(std::unique_ptr<sys::fs::mapped_file_region> Region,
375 TrieRecord::StorageKind SK, FileOffset IndexOffset)
376 : Region(std::
move(Region)), SK(SK), IndexOffset(IndexOffset) {
378 bool IsStandalone =
false;
380 case TrieRecord::StorageKind::Standalone:
381 case TrieRecord::StorageKind::StandaloneLeaf:
382 case TrieRecord::StorageKind::StandaloneLeaf0:
393 std::unique_ptr<sys::fs::mapped_file_region> Region;
394 TrieRecord::StorageKind SK;
395 FileOffset IndexOffset;
399template <
size_t NumShards>
class StandaloneDataMap {
400 static_assert(
isPowerOf2_64(NumShards),
"Expected power of 2");
403 uintptr_t insert(ArrayRef<uint8_t> Hash, TrieRecord::StorageKind SK,
404 std::unique_ptr<sys::fs::mapped_file_region> Region,
405 FileOffset IndexOffset);
407 const StandaloneDataInMemory *
lookup(ArrayRef<uint8_t> Hash)
const;
408 bool count(ArrayRef<uint8_t> Hash)
const {
return bool(
lookup(Hash)); }
413 DenseMap<const uint8_t *, std::unique_ptr<StandaloneDataInMemory>> Map;
414 mutable std::mutex Mutex;
416 Shard &getShard(ArrayRef<uint8_t> Hash) {
417 return const_cast<Shard &
>(
418 const_cast<const StandaloneDataMap *
>(
this)->getShard(Hash));
420 const Shard &getShard(ArrayRef<uint8_t> Hash)
const {
421 static_assert(NumShards <= 256,
"Expected only 8 bits of shard");
422 return Shards[Hash[0] % NumShards];
425 Shard Shards[NumShards];
428using StandaloneDataMapTy = StandaloneDataMap<16>;
431class InternalRefVector {
433 void push_back(InternalRef
Ref) {
435 return FullRefs.push_back(
Ref);
437 return SmallRefs.push_back(*Small);
440 FullRefs.reserve(SmallRefs.size() + 1);
441 for (InternalRef4B Small : SmallRefs)
442 FullRefs.push_back(Small);
443 FullRefs.push_back(
Ref);
447 operator InternalRefArrayRef()
const {
448 assert(SmallRefs.empty() || FullRefs.empty());
449 return NeedsFull ? InternalRefArrayRef(FullRefs)
450 : InternalRefArrayRef(SmallRefs);
454 bool NeedsFull =
false;
464 if (Expected<char *> Mem =
Alloc(
L.getTotalSize()))
465 return constructImpl(*Mem,
I, L);
467 return Mem.takeError();
490uintptr_t StandaloneDataMap<N>::insert(
492 std::unique_ptr<sys::fs::mapped_file_region>
Region,
494 auto &S = getShard(Hash);
495 std::lock_guard<std::mutex> Lock(S.Mutex);
496 auto &V = S.Map[Hash.
data()];
498 V = std::make_unique<StandaloneDataInMemory>(std::move(
Region), SK,
500 return reinterpret_cast<uintptr_t
>(V.get());
504const StandaloneDataInMemory *
506 auto &S = getShard(Hash);
507 std::lock_guard<std::mutex> Lock(S.Mutex);
508 auto I = S.Map.find(Hash.
data());
509 if (
I == S.Map.end())
529 TempFile(TempFile &&
Other) { *
this = std::move(
Other); }
530 TempFile &operator=(TempFile &&
Other) {
531 TmpName = std::move(
Other.TmpName);
545 OnDiskCASLogger *Logger =
nullptr;
548 Error keep(
const Twine &Name);
555class MappedTempFile {
557 char *
data()
const {
return Map.
data(); }
558 size_t size()
const {
return Map.
size(); }
561 assert(Map &&
"Map already destroyed");
563 return Temp.discard();
566 Error keep(
const Twine &Name) {
567 assert(Map &&
"Map already destroyed");
569 return Temp.keep(Name);
572 MappedTempFile(TempFile Temp, sys::fs::mapped_file_region Map)
577 sys::fs::mapped_file_region Map;
591 std::error_code RemoveEC;
632 Logger->logTempFileCreate(ResultPath);
634 TempFile Ret(ResultPath,
FD,
Logger);
635 return std::move(Ret);
638bool TrieRecord::compare_exchange_strong(
Data &Existing,
Data New) {
639 uint64_t ExistingPacked = pack(Existing);
641 if (Storage.compare_exchange_strong(ExistingPacked, NewPacked))
643 Existing = unpack(ExistingPacked);
650 auto HeaderData = Pool.
get(
Offset,
sizeof(DataRecordHandle::Header));
652 return HeaderData.takeError();
654 auto Record = DataRecordHandle::get(HeaderData->data());
658 "data record span passed the end of the data pool");
663DataRecordHandle DataRecordHandle::constructImpl(
char *Mem,
const Input &
I,
665 char *
Next = Mem +
sizeof(Header);
668 Header::PackTy Packed = 0;
669 Packed |= LayoutFlags::pack(L.Flags) << Header::LayoutFlagsShift;
672 switch (L.Flags.DataSize) {
673 case DataSizeFlags::Uses1B:
674 assert(
I.Data.size() <= UINT8_MAX);
675 Packed |= (Header::PackTy)
I.Data.size()
676 << ((
sizeof(Packed) - 2) * CHAR_BIT);
678 case DataSizeFlags::Uses2B:
679 assert(
I.Data.size() <= UINT16_MAX);
680 Packed |= (Header::PackTy)
I.Data.size()
681 << ((
sizeof(Packed) - 4) * CHAR_BIT);
683 case DataSizeFlags::Uses4B:
687 case DataSizeFlags::Uses8B:
697 switch (L.Flags.NumRefs) {
698 case NumRefsFlags::Uses0B:
700 case NumRefsFlags::Uses1B:
701 assert(
I.Refs.size() <= UINT8_MAX);
702 Packed |= (Header::PackTy)
I.Refs.size()
703 << ((
sizeof(Packed) - 2) * CHAR_BIT);
705 case NumRefsFlags::Uses2B:
706 assert(
I.Refs.size() <= UINT16_MAX);
707 Packed |= (Header::PackTy)
I.Refs.size()
708 << ((
sizeof(Packed) - 4) * CHAR_BIT);
710 case NumRefsFlags::Uses4B:
714 case NumRefsFlags::Uses8B:
721 if (!
I.Refs.empty()) {
722 assert((
L.Flags.RefKind == RefKindFlags::InternalRef4B) ==
I.Refs.is4B());
723 ArrayRef<uint8_t> RefsBuffer =
I.Refs.getBuffer();
731 Next[
I.Data.size()] = 0;
734 Header *
H =
new (Mem) Header{
Packed};
739 assert(
Record.getLayoutFlags().DataSize ==
L.Flags.DataSize);
745DataRecordHandle::Layout::Layout(
const Input &
I) {
747 uint64_t RelOffset =
sizeof(Header);
751 NumRefs =
I.Refs.size();
755 I.Refs.is4B() ? RefKindFlags::InternalRef4B : RefKindFlags::InternalRef;
760 if (
DataSize <= UINT8_MAX && Has1B) {
761 Flags.DataSize = DataSizeFlags::Uses1B;
763 }
else if (
DataSize <= UINT16_MAX && Has2B) {
764 Flags.DataSize = DataSizeFlags::Uses2B;
766 }
else if (
DataSize <= UINT32_MAX) {
767 Flags.DataSize = DataSizeFlags::Uses4B;
770 Flags.DataSize = DataSizeFlags::Uses8B;
776 Flags.NumRefs = NumRefsFlags::Uses0B;
777 }
else if (NumRefs <= UINT8_MAX && Has1B) {
778 Flags.NumRefs = NumRefsFlags::Uses1B;
780 }
else if (NumRefs <= UINT16_MAX && Has2B) {
781 Flags.NumRefs = NumRefsFlags::Uses2B;
784 Flags.NumRefs = NumRefsFlags::Uses4B;
795 auto GrowSizeFieldsBy4B = [&]() {
799 assert(Flags.NumRefs != NumRefsFlags::Uses8B &&
800 "Expected to be able to grow NumRefs8B");
806 if (Flags.DataSize < DataSizeFlags::Uses4B)
807 Flags.DataSize = DataSizeFlags::Uses4B;
808 else if (Flags.DataSize < DataSizeFlags::Uses8B)
809 Flags.DataSize = DataSizeFlags::Uses8B;
810 else if (Flags.NumRefs < NumRefsFlags::Uses4B)
811 Flags.NumRefs = NumRefsFlags::Uses4B;
813 Flags.NumRefs = NumRefsFlags::Uses8B;
817 if (Flags.RefKind == RefKindFlags::InternalRef) {
821 GrowSizeFieldsBy4B();
824 RefsRelOffset = RelOffset;
825 RelOffset += 8 * NumRefs;
833 uint64_t RefListSize = 4 * NumRefs;
835 GrowSizeFieldsBy4B();
836 RefsRelOffset = RelOffset;
837 RelOffset += RefListSize;
841 DataRelOffset = RelOffset;
844uint64_t DataRecordHandle::getDataSize()
const {
845 int64_t RelOffset =
sizeof(Header);
846 auto *DataSizePtr =
reinterpret_cast<const char *
>(
H) + RelOffset;
847 switch (getLayoutFlags().
DataSize) {
848 case DataSizeFlags::Uses1B:
849 return (
H->Packed >> ((
sizeof(Header::PackTy) - 2) * CHAR_BIT)) & UINT8_MAX;
850 case DataSizeFlags::Uses2B:
851 return (
H->Packed >> ((
sizeof(Header::PackTy) - 4) * CHAR_BIT)) &
853 case DataSizeFlags::Uses4B:
855 case DataSizeFlags::Uses8B:
861void DataRecordHandle::skipDataSize(LayoutFlags LF, int64_t &RelOffset)
const {
862 if (LF.DataSize >= DataSizeFlags::Uses4B)
864 if (LF.DataSize >= DataSizeFlags::Uses8B)
868uint32_t DataRecordHandle::getNumRefs()
const {
869 LayoutFlags LF = getLayoutFlags();
870 int64_t RelOffset =
sizeof(Header);
871 skipDataSize(LF, RelOffset);
872 auto *NumRefsPtr =
reinterpret_cast<const char *
>(
H) + RelOffset;
873 switch (LF.NumRefs) {
874 case NumRefsFlags::Uses0B:
876 case NumRefsFlags::Uses1B:
877 return (
H->Packed >> ((
sizeof(Header::PackTy) - 2) * CHAR_BIT)) & UINT8_MAX;
878 case NumRefsFlags::Uses2B:
879 return (
H->Packed >> ((
sizeof(Header::PackTy) - 4) * CHAR_BIT)) &
881 case NumRefsFlags::Uses4B:
883 case NumRefsFlags::Uses8B:
889void DataRecordHandle::skipNumRefs(LayoutFlags LF, int64_t &RelOffset)
const {
890 if (LF.NumRefs >= NumRefsFlags::Uses4B)
892 if (LF.NumRefs >= NumRefsFlags::Uses8B)
896int64_t DataRecordHandle::getRefsRelOffset()
const {
897 LayoutFlags LF = getLayoutFlags();
898 int64_t RelOffset =
sizeof(Header);
899 skipDataSize(LF, RelOffset);
900 skipNumRefs(LF, RelOffset);
904int64_t DataRecordHandle::getDataRelOffset()
const {
905 LayoutFlags LF = getLayoutFlags();
906 int64_t RelOffset =
sizeof(Header);
907 skipDataSize(LF, RelOffset);
908 skipNumRefs(LF, RelOffset);
909 uint32_t RefSize = LF.RefKind == RefKindFlags::InternalRef4B ? 4 : 8;
910 RelOffset += RefSize * getNumRefs();
916 if (
auto E = UpstreamDB->validate(Deep, Hasher))
921 "data pool bump pointer is not aligned");
925 auto formatError = [&](
Twine Msg) {
933 if (
Record.Data.size() !=
sizeof(TrieRecord))
934 return formatError(
"wrong data record size");
936 return formatError(
"wrong data record alignment");
938 auto *R =
reinterpret_cast<const TrieRecord *
>(
Record.Data.data());
939 TrieRecord::Data
D = R->load();
940 std::unique_ptr<MemoryBuffer> FileBuffer;
946 return formatError(
"invalid record kind value");
949 auto I = getIndexProxyFromRef(
Ref);
951 return I.takeError();
954 case TrieRecord::StorageKind::Unknown:
959 case TrieRecord::StorageKind::DataPool: {
962 if (
D.Offset.get() <= 0 ||
963 D.Offset.get() +
sizeof(DataRecordHandle::Header) >= DataPool.size())
964 return formatError(
"datapool record out of bound");
968 return formatError(
"data record offset is not aligned");
972 DataPool.get(
D.Offset,
sizeof(DataRecordHandle::Header));
974 return formatError(
toString(HeaderData.takeError()));
975 auto LF = DataRecordHandle::get(HeaderData->data()).getLayoutFlags();
976 if (LF.NumRefs > DataRecordHandle::NumRefsFlags::Max ||
977 LF.DataSize > DataRecordHandle::DataSizeFlags::Max)
978 return formatError(
"data record has invalid layout flags");
981 case TrieRecord::StorageKind::Standalone:
982 case TrieRecord::StorageKind::StandaloneLeaf:
983 case TrieRecord::StorageKind::StandaloneLeaf0:
993 return formatError(
"record file \'" + Path +
"\' does not exist");
995 FileBuffer = std::move(*File);
997 return formatError(
"record file \'" + Path +
"\' does not exist");
1003 auto dataError = [&](
Twine Msg) {
1005 "bad data for digest \'" +
toHex(
I->Hash) +
1006 "\': " + Msg.str());
1012 case TrieRecord::StorageKind::Unknown:
1014 case TrieRecord::StorageKind::DataPool: {
1015 auto DataRecord = DataRecordHandle::getFromDataPool(DataPool,
D.Offset);
1017 return dataError(
toString(DataRecord.takeError()));
1019 for (
auto InternRef : DataRecord->getRefs()) {
1020 if (InternRef.getFileOffset().get() <= 0)
1021 return dataError(
"invalid ref offset");
1022 auto Index = getIndexProxyFromRef(InternRef);
1024 return Index.takeError();
1027 StoredData = DataRecord->getData();
1030 case TrieRecord::StorageKind::Standalone: {
1031 if (FileBuffer->getBufferSize() <
sizeof(DataRecordHandle::Header))
1032 return dataError(
"data record is not big enough to read the header");
1033 auto DataRecord = DataRecordHandle::get(FileBuffer->getBufferStart());
1034 if (DataRecord.getTotalSize() < FileBuffer->getBufferSize())
1036 "data record span passed the end of the standalone file");
1037 for (
auto InternRef : DataRecord.getRefs()) {
1038 if (InternRef.getFileOffset().get() <= 0)
1039 return dataError(
"invalid ref offset");
1040 auto Index = getIndexProxyFromRef(InternRef);
1042 return Index.takeError();
1045 StoredData = DataRecord.getData();
1048 case TrieRecord::StorageKind::StandaloneLeaf:
1049 case TrieRecord::StorageKind::StandaloneLeaf0: {
1051 if (
D.SK == TrieRecord::StorageKind::StandaloneLeaf0) {
1052 if (!FileBuffer->getBuffer().ends_with(
'\0'))
1053 return dataError(
"standalone file is not zero terminated");
1061 Hasher(Refs, StoredData, ComputedHash);
1063 return dataError(
"hash mismatch, got \'" +
toHex(ComputedHash) +
1071 auto formatError = [&](
Twine Msg) {
1080 return formatError(
"zero is not a valid ref");
1090 return formatError(
"not found using hash " +
toHex(Hash));
1092 ObjectID OtherRef = getExternalReference(makeInternalRef(OtherI.
Offset));
1093 if (OtherRef != ExternalRef)
1094 return formatError(
"ref does not match indexed offset " +
1096 " for hash " +
toHex(Hash));
1101 OS <<
"on-disk-root-path: " << RootPath <<
"\n";
1113 auto *R =
reinterpret_cast<const TrieRecord *
>(
Data.data());
1114 TrieRecord::Data
D = R->load();
1117 case TrieRecord::StorageKind::Unknown:
1120 case TrieRecord::StorageKind::DataPool:
1124 case TrieRecord::StorageKind::Standalone:
1125 OS <<
"standalone-data ";
1127 case TrieRecord::StorageKind::StandaloneLeaf:
1128 OS <<
"standalone-leaf ";
1130 case TrieRecord::StorageKind::StandaloneLeaf0:
1131 OS <<
"standalone-leaf+0";
1134 OS <<
" Offset=" << (
void *)
D.Offset.get();
1142 Pool, [](PoolInfo LHS, PoolInfo RHS) {
return LHS.Offset < RHS.Offset; });
1143 for (PoolInfo PI : Pool) {
1144 OS <<
"- addr=" << (
void *)PI.Offset <<
" ";
1145 auto D = DataRecordHandle::getFromDataPool(DataPool,
FileOffset(PI.Offset));
1147 OS <<
"error: " <<
toString(
D.takeError());
1151 OS <<
"record refs=" <<
D->getNumRefs() <<
" data=" <<
D->getDataSize()
1152 <<
" size=" <<
D->getTotalSize()
1153 <<
" end=" << (
void *)(PI.Offset +
D->getTotalSize()) <<
"\n";
1159 auto P = Index.insertLazy(
1165 new (TentativeValue.
Data.
data()) TrieRecord();
1168 return P.takeError();
1170 assert(*
P &&
"Expected insertion");
1171 return getIndexProxyFromPointer(*
P);
1178 return IndexProxy{
P.getOffset(),
P->Hash,
1179 *
const_cast<TrieRecord *
>(
1180 reinterpret_cast<const TrieRecord *
>(
P->Data.data()))};
1184 auto I = indexHash(Hash);
1186 return I.takeError();
1187 return getExternalReference(*
I);
1190ObjectID OnDiskGraphDB::getExternalReference(
const IndexProxy &
I) {
1191 return getExternalReference(makeInternalRef(
I.Offset));
1194std::optional<ObjectID>
1196 bool CheckUpstream) {
1198 [&](std::optional<IndexProxy>
I) -> std::optional<ObjectID> {
1199 if (!CheckUpstream || !UpstreamDB)
1200 return std::nullopt;
1201 std::optional<ObjectID> UpstreamID =
1202 UpstreamDB->getExistingReference(Digest);
1204 return std::nullopt;
1207 return std::nullopt;
1210 return getExternalReference(*
I);
1215 return tryUpstream(std::nullopt);
1217 TrieRecord::Data Obj =
I.Ref.load();
1218 if (Obj.SK == TrieRecord::StorageKind::Unknown)
1219 return tryUpstream(
I);
1220 return getExternalReference(makeInternalRef(
I.Offset));
1225 auto P = Index.recoverFromFileOffset(
Ref.getFileOffset());
1227 return P.takeError();
1228 return getIndexProxyFromPointer(*
P);
1232 auto I = getIndexProxyFromRef(
Ref);
1234 return I.takeError();
1242static std::variant<const StandaloneDataInMemory *, DataRecordHandle>
1249 reinterpret_cast<const StandaloneDataInMemory *
>(
Data & (-1ULL << 1));
1255 assert(DataHandle.getData().end()[0] == 0 &&
"Null termination");
1262 if (std::holds_alternative<const StandaloneDataInMemory *>(SDIMOrRecord)) {
1263 return std::get<const StandaloneDataInMemory *>(SDIMOrRecord)->getContent();
1265 auto DataHandle = std::get<DataRecordHandle>(std::move(SDIMOrRecord));
1266 return OnDiskContent{std::move(DataHandle), std::nullopt};
1272 return Content.getData();
1276 if (std::optional<DataRecordHandle>
Record =
1278 return Record->getRefs();
1279 return std::nullopt;
1285 if (std::holds_alternative<const StandaloneDataInMemory *>(SDIMOrRecord)) {
1286 auto *SDIM = std::get<const StandaloneDataInMemory *>(SDIMOrRecord);
1287 return SDIM->getInternalFileBackedObjectData(RootPath);
1289 auto DataHandle = std::get<DataRecordHandle>(std::move(SDIMOrRecord));
1297 auto I = getIndexProxyFromRef(
Ref);
1299 return I.takeError();
1300 TrieRecord::Data Object =
I->Ref.load();
1302 if (Object.SK == TrieRecord::StorageKind::Unknown)
1303 return faultInFromUpstream(ExternalRef);
1305 if (Object.SK == TrieRecord::StorageKind::DataPool)
1315 switch (Object.SK) {
1316 case TrieRecord::StorageKind::Unknown:
1317 case TrieRecord::StorageKind::DataPool:
1319 case TrieRecord::StorageKind::Standalone:
1320 case TrieRecord::StorageKind::StandaloneLeaf0:
1321 case TrieRecord::StorageKind::StandaloneLeaf:
1347 auto Region = std::make_unique<sys::fs::mapped_file_region>(
1353 static_cast<StandaloneDataMapTy *
>(StandaloneData)
1354 ->insert(
I->Hash, Object.SK, std::move(
Region),
I->Offset));
1358 auto Presence = getObjectPresence(
Ref,
true);
1360 return Presence.takeError();
1362 switch (*Presence) {
1363 case ObjectPresence::Missing:
1365 case ObjectPresence::InPrimaryDB:
1367 case ObjectPresence::OnlyInUpstreamDB:
1368 if (
auto FaultInResult = faultInFromUpstream(
Ref); !FaultInResult)
1369 return FaultInResult.takeError();
1376OnDiskGraphDB::getObjectPresence(
ObjectID ExternalRef,
1377 bool CheckUpstream)
const {
1379 auto I = getIndexProxyFromRef(
Ref);
1381 return I.takeError();
1383 TrieRecord::Data Object =
I->Ref.load();
1384 if (Object.SK != TrieRecord::StorageKind::Unknown)
1385 return ObjectPresence::InPrimaryDB;
1387 if (!CheckUpstream || !UpstreamDB)
1388 return ObjectPresence::Missing;
1390 std::optional<ObjectID> UpstreamID =
1391 UpstreamDB->getExistingReference(getDigest(*
I));
1392 return UpstreamID.has_value() ? ObjectPresence::OnlyInUpstreamDB
1393 : ObjectPresence::Missing;
1403 Path.assign(RootPath.
begin(), RootPath.
end());
1408void OnDiskGraphDB::getStandalonePath(StringRef Prefix, FileOffset IndexOffset,
1409 SmallVectorImpl<char> &Path)
const {
1410 return ::getStandalonePath(RootPath, Prefix, IndexOffset, Path);
1413OnDiskContent StandaloneDataInMemory::getContent()
const {
1419 case TrieRecord::StorageKind::Standalone:
1421 case TrieRecord::StorageKind::StandaloneLeaf0:
1422 Leaf = Leaf0 =
true;
1424 case TrieRecord::StorageKind::StandaloneLeaf:
1431 assert(
Data.drop_back(Leaf0).end()[0] == 0 &&
1432 "Standalone node data missing null termination");
1433 return OnDiskContent{std::nullopt,
1437 DataRecordHandle
Record = DataRecordHandle::get(
Region->data());
1439 "Standalone object record missing null termination for data");
1440 return OnDiskContent{
Record, std::nullopt};
1443OnDiskGraphDB::FileBackedData
1444StandaloneDataInMemory::getInternalFileBackedObjectData(
1445 StringRef RootPath)
const {
1447 case TrieRecord::StorageKind::Unknown:
1448 case TrieRecord::StorageKind::DataPool:
1450 case TrieRecord::StorageKind::Standalone:
1451 return OnDiskGraphDB::FileBackedData{getContent().getData(),
1453 case TrieRecord::StorageKind::StandaloneLeaf0:
1454 case TrieRecord::StorageKind::StandaloneLeaf:
1455 bool IsFileNulTerminated = SK == TrieRecord::StorageKind::StandaloneLeaf0;
1456 SmallString<256>
Path;
1459 return OnDiskGraphDB::FileBackedData{
1460 getContent().getData(), OnDiskGraphDB::FileBackedData::FileInfoTy{
1461 std::string(Path), IsFileNulTerminated}};
1466static Expected<MappedTempFile>
1470 assert(
Size &&
"Unexpected request for an empty temp file");
1473 return File.takeError();
1487 return MappedTempFile(std::move(*File), std::move(Map));
1495Error OnDiskGraphDB::createStandaloneLeaf(IndexProxy &
I, ArrayRef<char>
Data) {
1496 assert(
Data.size() > TrieRecord::MaxEmbeddedSize &&
1497 "Expected a bigger file for external content...");
1500 TrieRecord::StorageKind SK = Leaf0 ? TrieRecord::StorageKind::StandaloneLeaf0
1501 : TrieRecord::StorageKind::StandaloneLeaf;
1503 SmallString<256>
Path;
1504 int64_t FileSize =
Data.size() + Leaf0;
1513 return File.takeError();
1523 TrieRecord::Data Existing;
1525 TrieRecord::Data Leaf{SK, FileOffset()};
1526 if (
I.Ref.compare_exchange_strong(Existing, Leaf)) {
1527 recordStandaloneSizeIncrease(FileSize);
1533 if (Existing.SK == TrieRecord::StorageKind::Unknown)
1541 auto I = getIndexProxyFromRef(getInternalRef(
ID));
1543 return I.takeError();
1547 TrieRecord::Data Existing =
I->Ref.load();
1548 if (Existing.SK != TrieRecord::StorageKind::Unknown)
1553 if (Refs.
empty() &&
Data.size() > TrieRecord::MaxEmbeddedSize)
1554 return createStandaloneLeaf(*
I,
Data);
1559 InternalRefVector InternalRefs;
1561 InternalRefs.push_back(getInternalRef(
Ref));
1565 DataRecordHandle::Input
Input{InternalRefs,
Data};
1568 TrieRecord::StorageKind SK = TrieRecord::StorageKind::Unknown;
1571 std::optional<MappedTempFile> File;
1572 std::optional<uint64_t> FileSize;
1575 TrieRecord::StorageKind::Standalone),
1578 return std::move(E);
1581 SK = TrieRecord::StorageKind::Standalone;
1582 return File->data();
1585 if (
Size <= TrieRecord::MaxEmbeddedSize) {
1586 SK = TrieRecord::StorageKind::DataPool;
1587 auto P = DataPool.allocate(
Size);
1589 char *NewAlloc =
nullptr;
1591 P.takeError(), [&](std::unique_ptr<StringError> E) ->
Error {
1592 if (E->convertToErrorCode() == std::errc::not_enough_memory)
1593 return AllocStandaloneFile(Size).moveInto(NewAlloc);
1594 return Error(std::move(E));
1598 return std::move(NewE);
1600 PoolOffset =
P->getOffset();
1602 dbgs() <<
"pool-alloc addr=" << (
void *)PoolOffset.
get()
1604 <<
" end=" << (
void *)(PoolOffset.
get() +
Size) <<
"\n";
1606 return (*P)->data();
1608 return AllocStandaloneFile(
Size);
1615 assert(
Record.getData().end()[0] == 0 &&
"Expected null-termination");
1617 assert(SK != TrieRecord::StorageKind::Unknown);
1618 assert(
bool(File) !=
bool(PoolOffset) &&
1619 "Expected either a mapped file or a pooled offset");
1625 TrieRecord::Data Existing =
I->Ref.load();
1627 TrieRecord::Data NewObject{SK, PoolOffset};
1629 if (Existing.SK == TrieRecord::StorageKind::Unknown) {
1631 if (
Error E = File->keep(Path))
1643 if (Existing.SK == TrieRecord::StorageKind::Unknown) {
1644 if (
I->Ref.compare_exchange_strong(Existing, NewObject)) {
1646 recordStandaloneSizeIncrease(*FileSize);
1652 if (Existing.SK == TrieRecord::StorageKind::Unknown)
1665 std::optional<InternalUpstreamImportKind> ImportKind) {
1666 auto I = getIndexProxyFromRef(getInternalRef(
ID));
1668 return I.takeError();
1672 TrieRecord::Data Existing =
I->Ref.load();
1673 if (Existing.SK != TrieRecord::StorageKind::Unknown)
1683 if (FileSize <= TrieRecord::MaxEmbeddedSize) {
1693 return ExpectedPath.takeError();
1696 TrieRecord::StorageKind SK;
1697 if (ImportKind.has_value()) {
1699 switch (*ImportKind) {
1700 case InternalUpstreamImportKind::Leaf:
1701 SK = TrieRecord::StorageKind::StandaloneLeaf;
1703 case InternalUpstreamImportKind::Leaf0:
1704 SK = TrieRecord::StorageKind::StandaloneLeaf0;
1709 SK = Leaf0 ? TrieRecord::StorageKind::StandaloneLeaf0
1710 : TrieRecord::StorageKind::StandaloneLeaf;
1726 SmallString<256> StandalonePath;
1733 TrieRecord::Data Existing;
1735 TrieRecord::Data Leaf{SK, FileOffset()};
1736 if (
I->Ref.compare_exchange_strong(Existing, Leaf)) {
1737 recordStandaloneSizeIncrease(FileSize);
1743 if (Existing.SK == TrieRecord::StorageKind::Unknown)
1749void OnDiskGraphDB::recordStandaloneSizeIncrease(
size_t SizeIncrease) {
1750 standaloneStorageSize().fetch_add(SizeIncrease, std::memory_order_relaxed);
1753std::atomic<uint64_t> &OnDiskGraphDB::standaloneStorageSize()
const {
1754 MutableArrayRef<uint8_t> UserHeader = DataPool.getUserHeader();
1755 assert(UserHeader.
size() ==
sizeof(std::atomic<uint64_t>));
1757 return *
reinterpret_cast<std::atomic<uint64_t> *
>(UserHeader.
data());
1760uint64_t OnDiskGraphDB::getStandaloneStorageSize()
const {
1761 return standaloneStorageSize().load(std::memory_order_relaxed);
1765 return Index.size() + DataPool.size() + getStandaloneStorageSize();
1769 unsigned IndexPercent = Index.size() * 100ULL / Index.capacity();
1770 unsigned DataPercent = DataPool.size() * 100ULL / DataPool.capacity();
1771 return std::max(IndexPercent, DataPercent);
1776 unsigned HashByteSize, OnDiskGraphDB *UpstreamDB,
1777 std::shared_ptr<OnDiskCASLogger> Logger,
1782 constexpr uint64_t MB = 1024ull * 1024ull;
1783 constexpr uint64_t GB = 1024ull * 1024ull * 1024ull;
1786 uint64_t MaxDataPoolSize = 24 * GB;
1789 MaxIndexSize = 1 * GB;
1790 MaxDataPoolSize = 2 * GB;
1795 return CustomSize.takeError();
1797 MaxIndexSize = MaxDataPoolSize = **CustomSize;
1801 std::optional<OnDiskTrieRawHashMap> Index;
1804 HashByteSize * CHAR_BIT,
1805 sizeof(TrieRecord), MaxIndexSize,
1808 return std::move(E);
1810 uint32_t UserHeaderSize =
sizeof(std::atomic<uint64_t>);
1814 std::optional<OnDiskDataAllocator> DataPool;
1820 MaxDataPoolSize, MB, UserHeaderSize, Logger,
1821 [](
void *UserHeaderPtr) {
1822 new (UserHeaderPtr) std::atomic<uint64_t>(0);
1824 .moveInto(DataPool))
1825 return std::move(E);
1826 if (DataPool->getUserHeader().size() != UserHeaderSize)
1828 "unexpected user header in '" + DataPoolPath +
1831 return std::unique_ptr<OnDiskGraphDB>(
1832 new OnDiskGraphDB(AbsPath, std::move(*Index), std::move(*DataPool),
1833 UpstreamDB, Policy, std::move(Logger)));
1839 std::shared_ptr<OnDiskCASLogger>
Logger)
1841 RootPath(RootPath.str()), UpstreamDB(UpstreamDB), FIPolicy(Policy),
1852 StandaloneData =
new StandaloneDataMapTy();
1856 delete static_cast<StandaloneDataMapTy *
>(StandaloneData);
1865 struct UpstreamCursor {
1882 auto enqueueNode = [&](
ObjectID PrimaryID, std::optional<ObjectHandle>
Node) {
1891 enqueueNode(PrimaryID, UpstreamNode);
1893 while (!CursorStack.
empty()) {
1894 UpstreamCursor &Cur = CursorStack.
back();
1895 if (Cur.RefI == Cur.RefE) {
1900 assert(PrimaryNodesStack.
size() >= Cur.RefsCount + 1);
1901 ObjectID PrimaryID = *(PrimaryNodesStack.
end() - Cur.RefsCount - 1);
1902 auto PrimaryRefs =
ArrayRef(PrimaryNodesStack)
1903 .slice(PrimaryNodesStack.
size() - Cur.RefsCount);
1904 if (
Error E = importUpstreamData(PrimaryID, PrimaryRefs, Cur.Node))
1907 PrimaryNodesStack.
truncate(PrimaryNodesStack.
size() - Cur.RefsCount);
1912 ObjectID UpstreamID = *(Cur.RefI++);
1913 auto PrimaryID =
getReference(UpstreamDB->getDigest(UpstreamID));
1915 return PrimaryID.takeError();
1920 enqueueNode(*PrimaryID, std::nullopt);
1923 Expected<std::optional<ObjectHandle>> UpstreamNode =
1924 UpstreamDB->load(UpstreamID);
1927 enqueueNode(*PrimaryID, *UpstreamNode);
1939 auto UpstreamRefs = UpstreamDB->getObjectRefs(UpstreamNode);
1942 for (ObjectID UpstreamRef : UpstreamRefs) {
1945 return Ref.takeError();
1949 return importUpstreamData(PrimaryID, Refs, UpstreamNode);
1957 if (PrimaryRefs.
empty()) {
1958 auto FBData = UpstreamDB->getInternalFileBackedObjectData(UpstreamNode);
1959 if (FBData.FileInfo.has_value()) {
1963 PrimaryID, FBData.FileInfo->FilePath,
1964 FBData.FileInfo->IsFileNulTerminated
1965 ? InternalUpstreamImportKind::Leaf0
1966 : InternalUpstreamImportKind::Leaf);
1970 auto Data = UpstreamDB->getObjectData(UpstreamNode);
1971 return store(PrimaryID, PrimaryRefs,
Data);
1974Expected<std::optional<ObjectHandle>>
1975OnDiskGraphDB::faultInFromUpstream(
ObjectID PrimaryID) {
1977 return std::nullopt;
1979 auto UpstreamID = UpstreamDB->getReference(
getDigest(PrimaryID));
1981 return UpstreamID.takeError();
1983 Expected<std::optional<ObjectHandle>> UpstreamNode =
1984 UpstreamDB->load(*UpstreamID);
1988 return std::nullopt;
1991 ? importSingleNode(PrimaryID, **UpstreamNode)
1992 : importFullTree(PrimaryID, **UpstreamNode))
1993 return std::move(
E);
1994 return load(PrimaryID);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Mark last scratch load
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_UNLIKELY(EXPR)
This file defines the DenseMap class.
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
static bool lookup(const GsymReader &GR, DataExtractor &Data, uint64_t &Offset, uint64_t BaseAddr, uint64_t Addr, SourceLocations &SrcLocs, llvm::Error &Err)
A Lookup helper functions.
This file declares interface for OnDiskCASLogger, an interface that can be used to log CAS events to ...
This file declares interface for OnDiskDataAllocator, a file backed data pool can be used to allocate...
static constexpr StringLiteral FilePrefixLeaf0
static constexpr StringLiteral DataPoolTableName
static constexpr StringLiteral FilePrefixObject
static constexpr StringLiteral FilePrefixLeaf
static constexpr StringLiteral IndexFilePrefix
static OnDiskContent getContentFromHandle(const OnDiskDataAllocator &DataPool, ObjectHandle OH)
static constexpr StringLiteral DataPoolFilePrefix
static Error createCorruptObjectError(Expected< ArrayRef< uint8_t > > ID)
static std::variant< const StandaloneDataInMemory *, DataRecordHandle > getStandaloneDataOrDataRecord(const OnDiskDataAllocator &DataPool, ObjectHandle OH)
static size_t getPageSize()
static void getStandalonePath(StringRef RootPath, StringRef Prefix, FileOffset IndexOffset, SmallVectorImpl< char > &Path)
static Expected< MappedTempFile > createTempFile(StringRef FinalPath, uint64_t Size, OnDiskCASLogger *Logger)
static constexpr StringLiteral IndexTableName
This declares OnDiskGraphDB, an ondisk CAS database with a fixed length hash.
This file declares interface for OnDiskTrieRawHashMap, a thread-safe and (mostly) lock-free hash map ...
Provides a library for accessing information about this process and other processes on the operating ...
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
ArrayRef< T > drop_back(size_t N=1) const
Drop the last N elements of the array.
bool empty() const
empty - Check if the array is empty.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
Logging utility - given an ordered specification of features, and assuming a scalar reward,...
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void reserve(size_type N)
void truncate(size_type N)
Like resize, but requires that N is less than size().
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
StringRef - Represent a constant reference to a string, i.e.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
FileOffset is a wrapper around uint64_t to represent the offset of data from the beginning of the fil...
Handle to a loaded object in a ObjectStore instance.
LLVM_ABI_FOR_TEST Expected< ArrayRef< char > > get(FileOffset Offset, size_t Size) const
Get the data of Size stored at the given Offset.
static LLVM_ABI_FOR_TEST Expected< OnDiskDataAllocator > create(const Twine &Path, const Twine &TableName, uint64_t MaxFileSize, std::optional< uint64_t > NewFileInitialSize, uint32_t UserHeaderSize=0, std::shared_ptr< ondisk::OnDiskCASLogger > Logger=nullptr, function_ref< void(void *)> UserHeaderInit=nullptr)
LLVM_ABI_FOR_TEST size_t size() const
OnDiskTrieRawHashMap is a persistent trie data structure used as hash maps.
static LLVM_ABI_FOR_TEST Expected< OnDiskTrieRawHashMap > create(const Twine &Path, const Twine &TrieName, size_t NumHashBits, uint64_t DataSize, uint64_t MaxFileSize, std::optional< uint64_t > NewFileInitialSize, std::shared_ptr< ondisk::OnDiskCASLogger > Logger=nullptr, std::optional< size_t > NewTableNumRootBits=std::nullopt, std::optional< size_t > NewTableNumSubtrieBits=std::nullopt)
Gets or creates a file at Path with a hash-mapped trie named TrieName.
static std::optional< InternalRef4B > tryToShrink(InternalRef Ref)
Shrink to 4B reference.
Array of internal node references.
Standard 8 byte reference inside OnDiskGraphDB.
static InternalRef getFromOffset(FileOffset Offset)
Handle for a loaded node object.
static ObjectHandle fromFileOffset(FileOffset Offset)
static ObjectHandle fromMemory(uintptr_t Ptr)
ObjectHandle(uint64_t Opaque)
uint64_t getOpaqueData() const
Interface for logging low-level on-disk cas operations.
On-disk CAS nodes database, independent of a particular hashing algorithm.
FaultInPolicy
How to fault-in nodes if an upstream database is used.
@ SingleNode
Copy only the requested node.
void print(raw_ostream &OS) const
LLVM_ABI_FOR_TEST Error validateObjectID(ObjectID ID) const
Checks that ID exists in the index.
LLVM_ABI_FOR_TEST Expected< std::optional< ObjectHandle > > load(ObjectID Ref)
Expected< bool > isMaterialized(ObjectID Ref)
Check whether the object associated with Ref is stored in the CAS.
Error validate(bool Deep, HashingFuncT Hasher) const
Validate the OnDiskGraphDB.
object_refs_range getObjectRefs(ObjectHandle Node) const
unsigned getHardStorageLimitUtilization() const
LLVM_ABI_FOR_TEST Error store(ObjectID ID, ArrayRef< ObjectID > Refs, ArrayRef< char > Data)
Associate data & references with a particular object ID.
ArrayRef< uint8_t > getDigest(ObjectID Ref) const
FileBackedData getInternalFileBackedObjectData(ObjectHandle Node) const
Provides access to the underlying file path, that represents an object leaf node, when available.
LLVM_ABI_FOR_TEST Error storeFile(ObjectID ID, StringRef FilePath)
Associates the data of a file with a particular object ID.
LLVM_ABI_FOR_TEST size_t getStorageSize() const
static LLVM_ABI_FOR_TEST Expected< std::unique_ptr< OnDiskGraphDB > > open(StringRef Path, StringRef HashName, unsigned HashByteSize, OnDiskGraphDB *UpstreamDB=nullptr, std::shared_ptr< OnDiskCASLogger > Logger=nullptr, FaultInPolicy Policy=FaultInPolicy::FullTree)
Open the on-disk store from a directory.
bool containsObject(ObjectID Ref, bool CheckUpstream=true) const
Check whether the object associated with Ref is stored in the CAS.
LLVM_ABI_FOR_TEST ~OnDiskGraphDB()
LLVM_ABI_FOR_TEST Expected< ObjectID > getReference(ArrayRef< uint8_t > Hash)
Form a reference for the provided hash.
function_ref< void( ArrayRef< ArrayRef< uint8_t > >, ArrayRef< char >, SmallVectorImpl< uint8_t > &)> HashingFuncT
Hashing function type for validation.
LLVM_ABI_FOR_TEST ArrayRef< char > getObjectData(ObjectHandle Node) const
LLVM_ABI_FOR_TEST std::optional< ObjectID > getExistingReference(ArrayRef< uint8_t > Digest, bool CheckUpstream=true)
Get an existing reference to the object Digest.
Helper RAII class for copying a file to a unique file path.
Error renameTo(StringRef RenameToPath)
Rename the new unique file to RenameToPath.
Expected< StringRef > createAndCopyFrom(StringRef ParentPath, StringRef CopyFromPath)
Create a new unique file path under ParentPath and copy the contents of CopyFromPath into it.
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
static unsigned getPageSizeEstimate()
Get the process's estimated page size.
LLVM_ABI Error keep(const Twine &Name)
static LLVM_ABI Expected< TempFile > create(const Twine &Model, unsigned Mode=all_read|all_write, OpenFlags ExtraFlags=OF_None)
This creates a temporary file with createUniqueFile and schedules it for deletion with sys::RemoveFil...
Represents the result of a call to sys::fs::status().
This class represents a memory mapped file.
LLVM_ABI size_t size() const
@ readonly
May only access map via const_data as read only.
@ readwrite
May access map via data and modify it. Written to path.
LLVM_ABI char * data() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
constexpr StringLiteral CASFormatVersion
The version for all the ondisk database files.
Expected< std::optional< uint64_t > > getOverriddenMaxMappingSize()
Retrieves an overridden maximum mapping size for CAS files, if any, speicified by LLVM_CAS_MAX_MAPPIN...
Expected< size_t > preallocateFileTail(int FD, size_t CurrentSize, size_t NewSize)
Allocate space for the file FD on disk, if the filesystem supports it.
bool useSmallMappingSize(const Twine &Path)
Whether to use a small file mapping for ondisk databases created in Path.
uint64_t getDataSize(const FuncRecordTy *Record)
Return the coverage map data size for the function.
uint64_t read64le(const void *P)
void write64le(void *P, uint64_t V)
void write32le(void *P, uint32_t V)
uint32_t read32le(const void *P)
LLVM_ABI std::error_code closeFile(file_t &F)
Close the file object.
LLVM_ABI std::error_code rename(const Twine &from, const Twine &to)
Rename from to to.
std::error_code resize_file_before_mapping_readwrite(int FD, uint64_t Size)
Resize FD to Size before mapping mapped_file_region::readwrite.
LLVM_ABI bool exists(const basic_file_status &status)
Does file exist?
@ OF_Append
The file should be opened in append mode.
LLVM_ABI std::error_code createUniqueFile(const Twine &Model, int &ResultFD, SmallVectorImpl< char > &ResultPath, OpenFlags Flags=OF_None, unsigned Mode=all_read|all_write)
Create a uniquely named file.
LLVM_ABI std::error_code remove(const Twine &path, bool IgnoreNonExisting=true)
Remove path.
@ CD_OpenExisting
CD_OpenExisting - When opening a file:
LLVM_ABI Expected< file_t > openNativeFileForRead(const Twine &Name, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
LLVM_ABI std::error_code create_directories(const Twine &path, bool IgnoreExisting=true, perms Perms=owner_all|group_all)
Create all the non-existent directories in path.
LLVM_ABI file_t convertFDToNativeFile(int FD)
Converts from a Posix file descriptor number to a native file handle.
LLVM_ABI std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
std::error_code file_size(const Twine &Path, uint64_t &Result)
Get file size.
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
ScopedSetting scopedDisable()
This is an optimization pass for GlobalISel generic memory operations.
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
ArrayRef< CharT > arrayRefFromStringRef(StringRef Input)
Construct a string ref from an array ref of unsigned chars.
std::error_code make_error_code(BitcodeError E)
bool isAligned(Align Lhs, uint64_t SizeInBytes)
Checks that SizeInBytes is a multiple of the alignment.
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
FunctionAddr VTableAddr uintptr_t uintptr_t DataSize
std::string utohexstr(uint64_t X, bool LowerCase=false, unsigned Width=0)
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
std::optional< T > expectedToOptional(Expected< T > &&E)
Convert an Expected to an Optional without doing anything.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ Ref
The access may reference the value stored in memory.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
FunctionAddr VTableAddr Next
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
ArrayRef(const T &OneElt) -> ArrayRef< T >
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
OutputIt copy(R &&Range, OutputIt Out)
void toHex(ArrayRef< uint8_t > Input, bool LowerCase, SmallVectorImpl< char > &Output)
Convert buffer Input to its hexadecimal representation. The returned string is double the size of Inp...
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
void consumeError(Error Err)
Consume a Error without doing anything.
bool isAddrAligned(Align Lhs, const void *Addr)
Checks that Addr is a multiple of the alignment.
Implement std::hash so that hash_code can be used in STL containers.
Proxy for an on-disk index record.
This struct is a compact representation of a valid (non-zero power of two) alignment.
static constexpr Align Of()
Allow constructions of constexpr Align from types.
Const value proxy to access the records stored in TrieRawHashMap.
Value proxy to access the records stored in TrieRawHashMap.
MutableArrayRef< char > Data
Encapsulates file info for an underlying object node.