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;
146 assert(
D.Offset.get() < (int64_t)(1ULL << 56));
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;
289 return DataRelOffset + DataSize + 1;
298 explicit Layout(
const Input &
I);
302 uint32_t NumRefs = 0;
303 int64_t RefsRelOffset = 0;
304 int64_t DataRelOffset = 0;
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 Expected<DataRecordHandle>
328 createWithError(function_ref<Expected<char *>(
size_t Size)>
Alloc,
331 static DataRecordHandle
get(
const char *Mem) {
332 return DataRecordHandle(
333 *
reinterpret_cast<const DataRecordHandle::Header *
>(Mem));
335 static Expected<DataRecordHandle>
336 getFromDataPool(
const OnDiskDataAllocator &Pool, FileOffset
Offset);
338 explicit operator bool()
const {
return H; }
339 const Header &getHeader()
const {
return *H; }
341 DataRecordHandle() =
default;
342 explicit DataRecordHandle(
const Header &H) : H(&H) {}
345 static DataRecordHandle constructImpl(
char *Mem,
const Input &
I,
347 const Header *H =
nullptr;
351struct OnDiskContent {
352 std::optional<DataRecordHandle> Record;
353 std::optional<ArrayRef<char>> Bytes;
355 ArrayRef<char> getData()
const {
358 assert(Record &&
"Expected record or bytes");
359 return Record->getData();
364class StandaloneDataInMemory {
366 OnDiskContent getContent()
const;
368 OnDiskGraphDB::FileBackedData
369 getInternalFileBackedObjectData(StringRef RootPath)
const;
376 std::unique_ptr<MemoryBuffer>
377 getStandaloneMemoryBuffer(StringRef RootPath, StringRef Name,
378 bool RequiresNullTerminator)
const;
380 StandaloneDataInMemory(std::unique_ptr<sys::fs::mapped_file_region> Region,
381 TrieRecord::StorageKind SK, FileOffset IndexOffset)
382 : Region(std::
move(Region)), SK(SK), IndexOffset(IndexOffset) {
384 bool IsStandalone =
false;
386 case TrieRecord::StorageKind::Standalone:
387 case TrieRecord::StorageKind::StandaloneLeaf:
388 case TrieRecord::StorageKind::StandaloneLeaf0:
399 std::unique_ptr<sys::fs::mapped_file_region> Region;
400 TrieRecord::StorageKind SK;
401 FileOffset IndexOffset;
405template <
size_t NumShards>
class StandaloneDataMap {
406 static_assert(
isPowerOf2_64(NumShards),
"Expected power of 2");
409 uintptr_t insert(ArrayRef<uint8_t> Hash, TrieRecord::StorageKind SK,
410 std::unique_ptr<sys::fs::mapped_file_region> Region,
411 FileOffset IndexOffset);
413 const StandaloneDataInMemory *
lookup(ArrayRef<uint8_t> Hash)
const;
414 bool count(ArrayRef<uint8_t> Hash)
const {
return bool(
lookup(Hash)); }
419 DenseMap<const uint8_t *, std::unique_ptr<StandaloneDataInMemory>> Map;
420 mutable std::mutex Mutex;
422 Shard &getShard(ArrayRef<uint8_t> Hash) {
423 return const_cast<Shard &
>(
424 const_cast<const StandaloneDataMap *
>(
this)->getShard(Hash));
426 const Shard &getShard(ArrayRef<uint8_t> Hash)
const {
427 static_assert(NumShards <= 256,
"Expected only 8 bits of shard");
428 return Shards[Hash[0] % NumShards];
431 Shard Shards[NumShards];
434using StandaloneDataMapTy = StandaloneDataMap<16>;
437class InternalRefVector {
439 void push_back(InternalRef
Ref) {
441 return FullRefs.push_back(
Ref);
443 return SmallRefs.push_back(*Small);
446 FullRefs.reserve(SmallRefs.size() + 1);
447 for (InternalRef4B Small : SmallRefs)
448 FullRefs.push_back(Small);
449 FullRefs.push_back(
Ref);
453 operator InternalRefArrayRef()
const {
454 assert(SmallRefs.empty() || FullRefs.empty());
455 return NeedsFull ? InternalRefArrayRef(FullRefs)
456 : InternalRefArrayRef(SmallRefs);
460 bool NeedsFull =
false;
470 if (Expected<char *> Mem =
Alloc(
L.getTotalSize()))
471 return constructImpl(*Mem,
I, L);
473 return Mem.takeError();
498 std::unique_ptr<sys::fs::mapped_file_region>
Region,
500 auto &S = getShard(Hash);
501 std::lock_guard<std::mutex> Lock(S.Mutex);
502 auto &V = S.Map[Hash.
data()];
504 V = std::make_unique<StandaloneDataInMemory>(std::move(
Region), SK,
506 return reinterpret_cast<uintptr_t>(V.get());
510const StandaloneDataInMemory *
512 auto &S = getShard(Hash);
513 std::lock_guard<std::mutex> Lock(S.Mutex);
514 auto I = S.Map.find(Hash.
data());
515 if (
I == S.Map.end())
535 TempFile(TempFile &&
Other) { *
this = std::move(
Other); }
536 TempFile &operator=(TempFile &&
Other) {
537 TmpName = std::move(
Other.TmpName);
551 OnDiskCASLogger *Logger =
nullptr;
554 Error keep(
const Twine &Name);
561class MappedTempFile {
563 char *
data()
const {
return Map.
data(); }
564 size_t size()
const {
return Map.
size(); }
567 assert(Map &&
"Map already destroyed");
569 return Temp.discard();
572 Error keep(
const Twine &Name) {
573 assert(Map &&
"Map already destroyed");
575 return Temp.keep(Name);
578 MappedTempFile(TempFile Temp, sys::fs::mapped_file_region Map)
583 sys::fs::mapped_file_region Map;
597 std::error_code RemoveEC;
638 Logger->logTempFileCreate(ResultPath);
640 TempFile Ret(ResultPath,
FD,
Logger);
641 return std::move(Ret);
644bool TrieRecord::compare_exchange_strong(
Data &Existing,
Data New) {
645 uint64_t ExistingPacked = pack(Existing);
646 uint64_t NewPacked = pack(New);
647 if (Storage.compare_exchange_strong(ExistingPacked, NewPacked))
649 Existing = unpack(ExistingPacked);
656 auto HeaderData = Pool.
get(
Offset,
sizeof(DataRecordHandle::Header));
658 return HeaderData.takeError();
660 auto Record = DataRecordHandle::get(HeaderData->data());
664 "data record span passed the end of the data pool");
669DataRecordHandle DataRecordHandle::constructImpl(
char *Mem,
const Input &
I,
671 char *
Next = Mem +
sizeof(Header);
674 Header::PackTy Packed = 0;
675 Packed |= LayoutFlags::pack(L.Flags) << Header::LayoutFlagsShift;
678 switch (L.Flags.DataSize) {
679 case DataSizeFlags::Uses1B:
680 assert(
I.Data.size() <= UINT8_MAX);
681 Packed |= (Header::PackTy)
I.Data.size()
682 << ((
sizeof(Packed) - 2) * CHAR_BIT);
684 case DataSizeFlags::Uses2B:
685 assert(
I.Data.size() <= UINT16_MAX);
686 Packed |= (Header::PackTy)
I.Data.size()
687 << ((
sizeof(Packed) - 4) * CHAR_BIT);
689 case DataSizeFlags::Uses4B:
693 case DataSizeFlags::Uses8B:
703 switch (L.Flags.NumRefs) {
704 case NumRefsFlags::Uses0B:
706 case NumRefsFlags::Uses1B:
707 assert(
I.Refs.size() <= UINT8_MAX);
708 Packed |= (Header::PackTy)
I.Refs.size()
709 << ((
sizeof(Packed) - 2) * CHAR_BIT);
711 case NumRefsFlags::Uses2B:
712 assert(
I.Refs.size() <= UINT16_MAX);
713 Packed |= (Header::PackTy)
I.Refs.size()
714 << ((
sizeof(Packed) - 4) * CHAR_BIT);
716 case NumRefsFlags::Uses4B:
720 case NumRefsFlags::Uses8B:
727 if (!
I.Refs.empty()) {
728 assert((
L.Flags.RefKind == RefKindFlags::InternalRef4B) ==
I.Refs.is4B());
729 ArrayRef<uint8_t> RefsBuffer =
I.Refs.getBuffer();
737 Next[
I.Data.size()] = 0;
740 Header *
H =
new (Mem) Header{
Packed};
745 assert(
Record.getLayoutFlags().DataSize ==
L.Flags.DataSize);
751DataRecordHandle::Layout::Layout(
const Input &
I) {
753 uint64_t RelOffset =
sizeof(Header);
756 DataSize =
I.Data.size();
757 NumRefs =
I.Refs.size();
761 I.Refs.is4B() ? RefKindFlags::InternalRef4B : RefKindFlags::InternalRef;
766 if (DataSize <= UINT8_MAX && Has1B) {
767 Flags.DataSize = DataSizeFlags::Uses1B;
769 }
else if (DataSize <= UINT16_MAX && Has2B) {
770 Flags.DataSize = DataSizeFlags::Uses2B;
772 }
else if (DataSize <= UINT32_MAX) {
773 Flags.DataSize = DataSizeFlags::Uses4B;
776 Flags.DataSize = DataSizeFlags::Uses8B;
782 Flags.NumRefs = NumRefsFlags::Uses0B;
783 }
else if (NumRefs <= UINT8_MAX && Has1B) {
784 Flags.NumRefs = NumRefsFlags::Uses1B;
786 }
else if (NumRefs <= UINT16_MAX && Has2B) {
787 Flags.NumRefs = NumRefsFlags::Uses2B;
790 Flags.NumRefs = NumRefsFlags::Uses4B;
801 auto GrowSizeFieldsBy4B = [&]() {
805 assert(Flags.NumRefs != NumRefsFlags::Uses8B &&
806 "Expected to be able to grow NumRefs8B");
812 if (Flags.DataSize < DataSizeFlags::Uses4B)
813 Flags.DataSize = DataSizeFlags::Uses4B;
814 else if (Flags.DataSize < DataSizeFlags::Uses8B)
815 Flags.DataSize = DataSizeFlags::Uses8B;
816 else if (Flags.NumRefs < NumRefsFlags::Uses4B)
817 Flags.NumRefs = NumRefsFlags::Uses4B;
819 Flags.NumRefs = NumRefsFlags::Uses8B;
823 if (Flags.RefKind == RefKindFlags::InternalRef) {
827 GrowSizeFieldsBy4B();
830 RefsRelOffset = RelOffset;
831 RelOffset += 8 * NumRefs;
841 GrowSizeFieldsBy4B();
842 RefsRelOffset = RelOffset;
843 RelOffset += RefListSize;
847 DataRelOffset = RelOffset;
850uint64_t DataRecordHandle::getDataSize()
const {
851 int64_t RelOffset =
sizeof(Header);
852 auto *DataSizePtr =
reinterpret_cast<const char *
>(
H) + RelOffset;
853 switch (getLayoutFlags().DataSize) {
854 case DataSizeFlags::Uses1B:
855 return (
H->Packed >> ((
sizeof(Header::PackTy) - 2) * CHAR_BIT)) & UINT8_MAX;
856 case DataSizeFlags::Uses2B:
857 return (
H->Packed >> ((
sizeof(Header::PackTy) - 4) * CHAR_BIT)) &
859 case DataSizeFlags::Uses4B:
861 case DataSizeFlags::Uses8B:
867void DataRecordHandle::skipDataSize(LayoutFlags LF, int64_t &RelOffset)
const {
868 if (LF.DataSize >= DataSizeFlags::Uses4B)
870 if (LF.DataSize >= DataSizeFlags::Uses8B)
874uint32_t DataRecordHandle::getNumRefs()
const {
875 LayoutFlags LF = getLayoutFlags();
876 int64_t RelOffset =
sizeof(Header);
877 skipDataSize(LF, RelOffset);
878 auto *NumRefsPtr =
reinterpret_cast<const char *
>(
H) + RelOffset;
879 switch (LF.NumRefs) {
880 case NumRefsFlags::Uses0B:
882 case NumRefsFlags::Uses1B:
883 return (
H->Packed >> ((
sizeof(Header::PackTy) - 2) * CHAR_BIT)) & UINT8_MAX;
884 case NumRefsFlags::Uses2B:
885 return (
H->Packed >> ((
sizeof(Header::PackTy) - 4) * CHAR_BIT)) &
887 case NumRefsFlags::Uses4B:
889 case NumRefsFlags::Uses8B:
895void DataRecordHandle::skipNumRefs(LayoutFlags LF, int64_t &RelOffset)
const {
896 if (LF.NumRefs >= NumRefsFlags::Uses4B)
898 if (LF.NumRefs >= NumRefsFlags::Uses8B)
902int64_t DataRecordHandle::getRefsRelOffset()
const {
903 LayoutFlags LF = getLayoutFlags();
904 int64_t RelOffset =
sizeof(Header);
905 skipDataSize(LF, RelOffset);
906 skipNumRefs(LF, RelOffset);
910int64_t DataRecordHandle::getDataRelOffset()
const {
911 LayoutFlags LF = getLayoutFlags();
912 int64_t RelOffset =
sizeof(Header);
913 skipDataSize(LF, RelOffset);
914 skipNumRefs(LF, RelOffset);
915 uint32_t RefSize = LF.RefKind == RefKindFlags::InternalRef4B ? 4 : 8;
916 RelOffset += RefSize * getNumRefs();
922 if (
auto E = UpstreamDB->validate(Deep, Hasher))
927 "data pool bump pointer is not aligned");
939 if (
Record.Data.size() !=
sizeof(TrieRecord))
940 return formatError(
"wrong data record size");
942 return formatError(
"wrong data record alignment");
944 auto *R =
reinterpret_cast<const TrieRecord *
>(
Record.Data.data());
945 TrieRecord::Data
D = R->load();
946 std::unique_ptr<MemoryBuffer> FileBuffer;
952 return formatError(
"invalid record kind value");
955 auto I = getIndexProxyFromRef(
Ref);
957 return I.takeError();
960 case TrieRecord::StorageKind::Unknown:
965 case TrieRecord::StorageKind::DataPool: {
968 if (
D.Offset.get() <= 0 ||
969 D.Offset.get() +
sizeof(DataRecordHandle::Header) >= DataPool.size())
970 return formatError(
"datapool record out of bound");
974 return formatError(
"data record offset is not aligned");
978 DataPool.get(
D.Offset,
sizeof(DataRecordHandle::Header));
980 return formatError(
toString(HeaderData.takeError()));
981 auto LF = DataRecordHandle::get(HeaderData->data()).getLayoutFlags();
982 if (LF.NumRefs > DataRecordHandle::NumRefsFlags::Max ||
983 LF.DataSize > DataRecordHandle::DataSizeFlags::Max)
984 return formatError(
"data record has invalid layout flags");
987 case TrieRecord::StorageKind::Standalone:
988 case TrieRecord::StorageKind::StandaloneLeaf:
989 case TrieRecord::StorageKind::StandaloneLeaf0:
999 return formatError(
"record file \'" + Path +
"\' does not exist");
1001 FileBuffer = std::move(*File);
1003 return formatError(
"record file \'" + Path +
"\' does not exist");
1011 "bad data for digest \'" +
toHex(
I->Hash) +
1018 case TrieRecord::StorageKind::Unknown:
1020 case TrieRecord::StorageKind::DataPool: {
1021 auto DataRecord = DataRecordHandle::getFromDataPool(DataPool,
D.Offset);
1023 return dataError(
toString(DataRecord.takeError()));
1025 for (
auto InternRef : DataRecord->getRefs()) {
1026 if (InternRef.getFileOffset().get() <= 0)
1027 return dataError(
"invalid ref offset");
1028 auto Index = getIndexProxyFromRef(InternRef);
1030 return Index.takeError();
1033 StoredData = DataRecord->getData();
1036 case TrieRecord::StorageKind::Standalone: {
1037 if (FileBuffer->getBufferSize() <
sizeof(DataRecordHandle::Header))
1038 return dataError(
"data record is not big enough to read the header");
1039 auto DataRecord = DataRecordHandle::get(FileBuffer->getBufferStart());
1040 if (DataRecord.getTotalSize() < FileBuffer->getBufferSize())
1042 "data record span passed the end of the standalone file");
1043 for (
auto InternRef : DataRecord.getRefs()) {
1044 if (InternRef.getFileOffset().get() <= 0)
1045 return dataError(
"invalid ref offset");
1046 auto Index = getIndexProxyFromRef(InternRef);
1048 return Index.takeError();
1051 StoredData = DataRecord.getData();
1054 case TrieRecord::StorageKind::StandaloneLeaf:
1055 case TrieRecord::StorageKind::StandaloneLeaf0: {
1057 if (
D.SK == TrieRecord::StorageKind::StandaloneLeaf0) {
1058 if (!FileBuffer->getBuffer().ends_with(
'\0'))
1059 return dataError(
"standalone file is not zero terminated");
1067 Hasher(Refs, StoredData, ComputedHash);
1069 return dataError(
"hash mismatch, got \'" +
toHex(ComputedHash) +
1077 auto formatError = [&](
Twine Msg) {
1086 return formatError(
"zero is not a valid ref");
1096 return formatError(
"not found using hash " +
toHex(Hash));
1098 ObjectID OtherRef = getExternalReference(makeInternalRef(OtherI.
Offset));
1099 if (OtherRef != ExternalRef)
1100 return formatError(
"ref does not match indexed offset " +
1102 " for hash " +
toHex(Hash));
1107 OS <<
"on-disk-root-path: " << RootPath <<
"\n";
1119 auto *R =
reinterpret_cast<const TrieRecord *
>(
Data.data());
1120 TrieRecord::Data
D = R->load();
1123 case TrieRecord::StorageKind::Unknown:
1126 case TrieRecord::StorageKind::DataPool:
1130 case TrieRecord::StorageKind::Standalone:
1131 OS <<
"standalone-data ";
1133 case TrieRecord::StorageKind::StandaloneLeaf:
1134 OS <<
"standalone-leaf ";
1136 case TrieRecord::StorageKind::StandaloneLeaf0:
1137 OS <<
"standalone-leaf+0";
1140 OS <<
" Offset=" << (
void *)
D.Offset.get();
1148 Pool, [](PoolInfo LHS, PoolInfo RHS) {
return LHS.Offset < RHS.Offset; });
1149 for (PoolInfo PI : Pool) {
1150 OS <<
"- addr=" << (
void *)PI.Offset <<
" ";
1151 auto D = DataRecordHandle::getFromDataPool(DataPool,
FileOffset(PI.Offset));
1153 OS <<
"error: " <<
toString(
D.takeError());
1157 OS <<
"record refs=" <<
D->getNumRefs() <<
" data=" <<
D->getDataSize()
1158 <<
" size=" <<
D->getTotalSize()
1159 <<
" end=" << (
void *)(PI.Offset +
D->getTotalSize()) <<
"\n";
1165 auto P = Index.insertLazy(
1171 new (TentativeValue.
Data.
data()) TrieRecord();
1174 return P.takeError();
1176 assert(*
P &&
"Expected insertion");
1177 return getIndexProxyFromPointer(*
P);
1184 return IndexProxy{
P.getOffset(),
P->Hash,
1185 *
const_cast<TrieRecord *
>(
1186 reinterpret_cast<const TrieRecord *
>(
P->Data.data()))};
1190 auto I = indexHash(Hash);
1192 return I.takeError();
1193 return getExternalReference(*
I);
1196ObjectID OnDiskGraphDB::getExternalReference(
const IndexProxy &
I) {
1197 return getExternalReference(makeInternalRef(
I.Offset));
1200std::optional<ObjectID>
1202 bool CheckUpstream) {
1204 [&](std::optional<IndexProxy>
I) -> std::optional<ObjectID> {
1205 if (!CheckUpstream || !UpstreamDB)
1206 return std::nullopt;
1207 std::optional<ObjectID> UpstreamID =
1208 UpstreamDB->getExistingReference(Digest);
1210 return std::nullopt;
1213 return std::nullopt;
1216 return getExternalReference(*
I);
1221 return tryUpstream(std::nullopt);
1223 TrieRecord::Data Obj =
I.Ref.load();
1224 if (Obj.SK == TrieRecord::StorageKind::Unknown)
1225 return tryUpstream(
I);
1226 return getExternalReference(makeInternalRef(
I.Offset));
1231 auto P = Index.recoverFromFileOffset(
Ref.getFileOffset());
1233 return P.takeError();
1234 return getIndexProxyFromPointer(*
P);
1238 auto I = getIndexProxyFromRef(
Ref);
1240 return I.takeError();
1248static std::variant<const StandaloneDataInMemory *, DataRecordHandle>
1255 reinterpret_cast<const StandaloneDataInMemory *
>(
Data & (-1ULL << 1));
1261 assert(DataHandle.getData().end()[0] == 0 &&
"Null termination");
1268 if (std::holds_alternative<const StandaloneDataInMemory *>(SDIMOrRecord)) {
1269 return std::get<const StandaloneDataInMemory *>(SDIMOrRecord)->getContent();
1271 auto DataHandle = std::get<DataRecordHandle>(std::move(SDIMOrRecord));
1272 return OnDiskContent{std::move(DataHandle), std::nullopt};
1278 return Content.getData();
1282 if (std::optional<DataRecordHandle>
Record =
1284 return Record->getRefs();
1285 return std::nullopt;
1291 if (std::holds_alternative<const StandaloneDataInMemory *>(SDIMOrRecord)) {
1292 auto *SDIM = std::get<const StandaloneDataInMemory *>(SDIMOrRecord);
1293 return SDIM->getInternalFileBackedObjectData(RootPath);
1295 auto DataHandle = std::get<DataRecordHandle>(std::move(SDIMOrRecord));
1300std::unique_ptr<MemoryBuffer>
1302 bool RequiresNullTerminator)
const {
1307 std::get_if<const StandaloneDataInMemory *>(&SDIMOrRecord)) {
1308 if (std::unique_ptr<MemoryBuffer> Standalone =
1309 (*SDIM)->getStandaloneMemoryBuffer(RootPath, Name,
1310 RequiresNullTerminator))
1320 auto I = getIndexProxyFromRef(
Ref);
1322 return I.takeError();
1323 TrieRecord::Data Object =
I->Ref.load();
1325 if (Object.SK == TrieRecord::StorageKind::Unknown)
1326 return faultInFromUpstream(ExternalRef);
1328 if (Object.SK == TrieRecord::StorageKind::DataPool)
1338 switch (Object.SK) {
1339 case TrieRecord::StorageKind::Unknown:
1340 case TrieRecord::StorageKind::DataPool:
1342 case TrieRecord::StorageKind::Standalone:
1343 case TrieRecord::StorageKind::StandaloneLeaf0:
1344 case TrieRecord::StorageKind::StandaloneLeaf:
1349 auto *StandaloneMap =
static_cast<StandaloneDataMapTy *
>(StandaloneData);
1350 if (
const StandaloneDataInMemory *SDIM = StandaloneMap->lookup(
I->Hash))
1375 auto Region = std::make_unique<sys::fs::mapped_file_region>(
1381 StandaloneMap->insert(
I->Hash, Object.SK, std::move(
Region),
I->Offset));
1385 auto Presence = getObjectPresence(
Ref,
true);
1387 return Presence.takeError();
1389 switch (*Presence) {
1390 case ObjectPresence::Missing:
1392 case ObjectPresence::InPrimaryDB:
1394 case ObjectPresence::OnlyInUpstreamDB:
1395 if (
auto FaultInResult = faultInFromUpstream(
Ref); !FaultInResult)
1396 return FaultInResult.takeError();
1403OnDiskGraphDB::getObjectPresence(
ObjectID ExternalRef,
1404 bool CheckUpstream)
const {
1406 auto I = getIndexProxyFromRef(
Ref);
1408 return I.takeError();
1410 TrieRecord::Data Object =
I->Ref.load();
1411 if (Object.SK != TrieRecord::StorageKind::Unknown)
1412 return ObjectPresence::InPrimaryDB;
1414 if (!CheckUpstream || !UpstreamDB)
1415 return ObjectPresence::Missing;
1417 std::optional<ObjectID> UpstreamID =
1418 UpstreamDB->getExistingReference(getDigest(*
I));
1419 return UpstreamID.has_value() ? ObjectPresence::OnlyInUpstreamDB
1420 : ObjectPresence::Missing;
1430 Path.assign(RootPath.
begin(), RootPath.
end());
1435void OnDiskGraphDB::getStandalonePath(StringRef Prefix, FileOffset IndexOffset,
1436 SmallVectorImpl<char> &Path)
const {
1437 return ::getStandalonePath(RootPath, Prefix, IndexOffset, Path);
1440OnDiskContent StandaloneDataInMemory::getContent()
const {
1446 case TrieRecord::StorageKind::Standalone:
1448 case TrieRecord::StorageKind::StandaloneLeaf0:
1449 Leaf = Leaf0 =
true;
1451 case TrieRecord::StorageKind::StandaloneLeaf:
1458 assert(
Data.drop_back(Leaf0).end()[0] == 0 &&
1459 "Standalone node data missing null termination");
1460 return OnDiskContent{std::nullopt,
1464 DataRecordHandle
Record = DataRecordHandle::get(
Region->data());
1466 "Standalone object record missing null termination for data");
1467 return OnDiskContent{
Record, std::nullopt};
1470OnDiskGraphDB::FileBackedData
1471StandaloneDataInMemory::getInternalFileBackedObjectData(
1472 StringRef RootPath)
const {
1474 case TrieRecord::StorageKind::Unknown:
1475 case TrieRecord::StorageKind::DataPool:
1477 case TrieRecord::StorageKind::Standalone:
1478 return OnDiskGraphDB::FileBackedData{getContent().getData(),
1480 case TrieRecord::StorageKind::StandaloneLeaf0:
1481 case TrieRecord::StorageKind::StandaloneLeaf:
1482 bool IsFileNulTerminated = SK == TrieRecord::StorageKind::StandaloneLeaf0;
1483 SmallString<256>
Path;
1486 return OnDiskGraphDB::FileBackedData{
1487 getContent().getData(), OnDiskGraphDB::FileBackedData::FileInfoTy{
1488 std::string(Path), IsFileNulTerminated}};
1496class AdoptedMemoryBuffer final :
public MemoryBuffer {
1498 AdoptedMemoryBuffer(std::unique_ptr<MemoryBuffer> Buffer, StringRef Name,
1501 const char *
Start = this->Buffer->getBufferStart() +
Offset;
1505 StringRef getBufferIdentifier()
const final {
return Name; }
1507 BufferKind getBufferKind()
const final {
return Buffer->getBufferKind(); }
1510 std::unique_ptr<MemoryBuffer> Buffer;
1515std::unique_ptr<MemoryBuffer> StandaloneDataInMemory::getStandaloneMemoryBuffer(
1516 StringRef RootPath, StringRef Name,
bool RequiresNullTerminator)
const {
1520 if (RequiresNullTerminator && SK == TrieRecord::StorageKind::StandaloneLeaf)
1527 SmallString<256>
Path;
1531 ErrorOr<std::unique_ptr<MemoryBuffer>> Mapped =
1540 OnDiskContent Content = getContent();
1541 ArrayRef<char>
Data = Content.getData();
1543 if (
Offset +
Data.size() > (*Mapped)->getBufferSize())
1546 return std::make_unique<AdoptedMemoryBuffer>(std::move(*Mapped), Name,
Offset,
1550static Expected<MappedTempFile>
1554 assert(
Size &&
"Unexpected request for an empty temp file");
1557 return File.takeError();
1571 return MappedTempFile(std::move(*File), std::move(Map));
1579Error OnDiskGraphDB::createStandaloneLeaf(IndexProxy &
I, ArrayRef<char>
Data) {
1580 assert(
Data.size() > TrieRecord::MaxEmbeddedSize &&
1581 "Expected a bigger file for external content...");
1584 TrieRecord::StorageKind SK = Leaf0 ? TrieRecord::StorageKind::StandaloneLeaf0
1585 : TrieRecord::StorageKind::StandaloneLeaf;
1587 SmallString<256>
Path;
1588 int64_t FileSize =
Data.size() + Leaf0;
1595 return File.takeError();
1605 TrieRecord::Data Existing;
1607 TrieRecord::Data Leaf{SK, FileOffset()};
1608 if (
I.Ref.compare_exchange_strong(Existing, Leaf)) {
1609 recordStandaloneSizeIncrease(FileSize);
1615 if (Existing.SK == TrieRecord::StorageKind::Unknown)
1623 auto I = getIndexProxyFromRef(getInternalRef(ID));
1625 return I.takeError();
1629 TrieRecord::Data Existing =
I->Ref.load();
1630 if (Existing.SK != TrieRecord::StorageKind::Unknown)
1637 if (Refs.
empty() &&
Data.size() > TrieRecord::MaxEmbeddedSize)
1638 return createStandaloneLeaf(*
I,
Data);
1643 InternalRefVector InternalRefs;
1645 InternalRefs.push_back(getInternalRef(
Ref));
1649 DataRecordHandle::Input
Input{InternalRefs,
Data};
1652 TrieRecord::StorageKind SK = TrieRecord::StorageKind::Unknown;
1655 std::optional<MappedTempFile> File;
1656 std::optional<uint64_t> FileSize;
1659 TrieRecord::StorageKind::Standalone),
1662 return std::move(E);
1665 SK = TrieRecord::StorageKind::Standalone;
1666 return File->data();
1669 if (
Size <= TrieRecord::MaxEmbeddedSize) {
1670 SK = TrieRecord::StorageKind::DataPool;
1671 auto P = DataPool.allocate(
Size);
1673 char *NewAlloc =
nullptr;
1675 P.takeError(), [&](std::unique_ptr<StringError> E) ->
Error {
1676 if (E->convertToErrorCode() == std::errc::not_enough_memory)
1677 return AllocStandaloneFile(Size).moveInto(NewAlloc);
1678 return Error(std::move(E));
1682 return std::move(NewE);
1684 PoolOffset =
P->getOffset();
1686 dbgs() <<
"pool-alloc addr=" << (
void *)PoolOffset.
get()
1688 <<
" end=" << (
void *)(PoolOffset.
get() +
Size) <<
"\n";
1690 return (*P)->data();
1692 return AllocStandaloneFile(
Size);
1699 assert(
Record.getData().end()[0] == 0 &&
"Expected null-termination");
1701 assert(SK != TrieRecord::StorageKind::Unknown);
1702 assert(
bool(File) !=
bool(PoolOffset) &&
1703 "Expected either a mapped file or a pooled offset");
1709 TrieRecord::Data Existing =
I->Ref.load();
1711 TrieRecord::Data NewObject{SK, PoolOffset};
1713 if (Existing.SK == TrieRecord::StorageKind::Unknown) {
1715 if (
Error E = File->keep(Path))
1727 if (Existing.SK == TrieRecord::StorageKind::Unknown) {
1728 if (
I->Ref.compare_exchange_strong(Existing, NewObject)) {
1730 recordStandaloneSizeIncrease(*FileSize);
1736 if (Existing.SK == TrieRecord::StorageKind::Unknown)
1744 return storeFile(ID, FilePath, std::nullopt);
1749 std::optional<InternalUpstreamImportKind> ImportKind) {
1750 auto I = getIndexProxyFromRef(getInternalRef(ID));
1752 return I.takeError();
1756 TrieRecord::Data Existing =
I->Ref.load();
1757 if (Existing.SK != TrieRecord::StorageKind::Unknown)
1767 if (FileSize <= TrieRecord::MaxEmbeddedSize) {
1777 return ExpectedPath.takeError();
1780 TrieRecord::StorageKind SK;
1781 if (ImportKind.has_value()) {
1783 switch (*ImportKind) {
1784 case InternalUpstreamImportKind::Leaf:
1785 SK = TrieRecord::StorageKind::StandaloneLeaf;
1787 case InternalUpstreamImportKind::Leaf0:
1788 SK = TrieRecord::StorageKind::StandaloneLeaf0;
1793 SK = Leaf0 ? TrieRecord::StorageKind::StandaloneLeaf0
1794 : TrieRecord::StorageKind::StandaloneLeaf;
1810 SmallString<256> StandalonePath;
1817 TrieRecord::Data Existing;
1819 TrieRecord::Data Leaf{SK, FileOffset()};
1820 if (
I->Ref.compare_exchange_strong(Existing, Leaf)) {
1821 recordStandaloneSizeIncrease(FileSize);
1827 if (Existing.SK == TrieRecord::StorageKind::Unknown)
1833void OnDiskGraphDB::recordStandaloneSizeIncrease(
size_t SizeIncrease) {
1834 standaloneStorageSize().fetch_add(SizeIncrease, std::memory_order_relaxed);
1837std::atomic<uint64_t> &OnDiskGraphDB::standaloneStorageSize()
const {
1838 MutableArrayRef<uint8_t> UserHeader = DataPool.getUserHeader();
1839 assert(UserHeader.
size() ==
sizeof(std::atomic<uint64_t>));
1841 return *
reinterpret_cast<std::atomic<uint64_t> *
>(UserHeader.
data());
1844uint64_t OnDiskGraphDB::getStandaloneStorageSize()
const {
1845 return standaloneStorageSize().load(std::memory_order_relaxed);
1849 return Index.size() + DataPool.size() + getStandaloneStorageSize();
1853 unsigned IndexPercent = Index.size() * 100ULL / Index.capacity();
1854 unsigned DataPercent = DataPool.size() * 100ULL / DataPool.capacity();
1855 return std::max(IndexPercent, DataPercent);
1860 unsigned HashByteSize, OnDiskGraphDB *UpstreamDB,
1861 std::shared_ptr<OnDiskCASLogger> Logger,
1866 constexpr uint64_t MB = 1024ull * 1024ull;
1867 constexpr uint64_t GB = 1024ull * 1024ull * 1024ull;
1869 uint64_t MaxIndexSize = 12 * GB;
1870 uint64_t MaxDataPoolSize = 24 * GB;
1873 MaxIndexSize = 1 * GB;
1874 MaxDataPoolSize = 2 * GB;
1879 return CustomSize.takeError();
1881 MaxIndexSize = MaxDataPoolSize = **CustomSize;
1885 std::optional<OnDiskTrieRawHashMap> Index;
1888 HashByteSize * CHAR_BIT,
1889 sizeof(TrieRecord), MaxIndexSize,
1892 return std::move(E);
1894 uint32_t UserHeaderSize =
sizeof(std::atomic<uint64_t>);
1898 std::optional<OnDiskDataAllocator> DataPool;
1904 MaxDataPoolSize, MB, UserHeaderSize, Logger,
1905 [](
void *UserHeaderPtr) {
1906 new (UserHeaderPtr) std::atomic<uint64_t>(0);
1908 .moveInto(DataPool))
1909 return std::move(E);
1910 if (DataPool->getUserHeader().size() != UserHeaderSize)
1912 "unexpected user header in '" + DataPoolPath +
1915 return std::unique_ptr<OnDiskGraphDB>(
1916 new OnDiskGraphDB(AbsPath, std::move(*Index), std::move(*DataPool),
1917 UpstreamDB, Policy, std::move(Logger)));
1923 std::shared_ptr<OnDiskCASLogger>
Logger)
1925 RootPath(RootPath.str()), UpstreamDB(UpstreamDB), FIPolicy(Policy),
1936 StandaloneData =
new StandaloneDataMapTy();
1940 delete static_cast<StandaloneDataMapTy *
>(StandaloneData);
1949 struct UpstreamCursor {
1966 auto enqueueNode = [&](
ObjectID PrimaryID, std::optional<ObjectHandle>
Node) {
1975 enqueueNode(PrimaryID, UpstreamNode);
1977 while (!CursorStack.
empty()) {
1978 UpstreamCursor &Cur = CursorStack.
back();
1979 if (Cur.RefI == Cur.RefE) {
1984 assert(PrimaryNodesStack.
size() >= Cur.RefsCount + 1);
1985 ObjectID PrimaryID = *(PrimaryNodesStack.
end() - Cur.RefsCount - 1);
1986 auto PrimaryRefs =
ArrayRef(PrimaryNodesStack)
1987 .slice(PrimaryNodesStack.
size() - Cur.RefsCount);
1988 if (
Error E = importUpstreamData(PrimaryID, PrimaryRefs, Cur.Node))
1991 PrimaryNodesStack.
truncate(PrimaryNodesStack.
size() - Cur.RefsCount);
1996 ObjectID UpstreamID = *(Cur.RefI++);
1997 auto PrimaryID =
getReference(UpstreamDB->getDigest(UpstreamID));
1999 return PrimaryID.takeError();
2004 enqueueNode(*PrimaryID, std::nullopt);
2007 Expected<std::optional<ObjectHandle>> UpstreamNode =
2008 UpstreamDB->load(UpstreamID);
2011 enqueueNode(*PrimaryID, *UpstreamNode);
2023 auto UpstreamRefs = UpstreamDB->getObjectRefs(UpstreamNode);
2026 for (ObjectID UpstreamRef : UpstreamRefs) {
2029 return Ref.takeError();
2033 return importUpstreamData(PrimaryID, Refs, UpstreamNode);
2041 if (PrimaryRefs.
empty()) {
2042 auto FBData = UpstreamDB->getInternalFileBackedObjectData(UpstreamNode);
2043 if (FBData.FileInfo.has_value()) {
2047 PrimaryID, FBData.FileInfo->FilePath,
2048 FBData.FileInfo->IsFileNulTerminated
2049 ? InternalUpstreamImportKind::Leaf0
2050 : InternalUpstreamImportKind::Leaf);
2054 auto Data = UpstreamDB->getObjectData(UpstreamNode);
2055 return store(PrimaryID, PrimaryRefs,
Data);
2058Expected<std::optional<ObjectHandle>>
2059OnDiskGraphDB::faultInFromUpstream(
ObjectID PrimaryID) {
2061 return std::nullopt;
2063 auto UpstreamID = UpstreamDB->getReference(
getDigest(PrimaryID));
2065 return UpstreamID.takeError();
2067 Expected<std::optional<ObjectHandle>> UpstreamNode =
2068 UpstreamDB->load(*UpstreamID);
2072 return std::nullopt;
2075 ? importSingleNode(PrimaryID, **UpstreamNode)
2076 : importFullTree(PrimaryID, **UpstreamNode))
2077 return std::move(
E);
2078 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, GsymDataExtractor &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 scope_exit class, which executes user-defined cleanup logic at scope exit.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
ArrayRef< T > drop_back(size_t N=1) const
Drop the last N elements of the array.
bool empty() const
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 std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")
Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it.
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...
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 Expected< ArrayRef< char > > get(FileOffset Offset, size_t Size) const
Get the data of Size stored at the given Offset.
static LLVM_ABI 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 size_t size() const
OnDiskTrieRawHashMap is a persistent trie data structure used as hash maps.
static LLVM_ABI 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 LLVM_ABI ObjectHandle fromFileOffset(FileOffset Offset)
static LLVM_ABI 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.
LLVM_ABI void print(raw_ostream &OS) const
LLVM_ABI Error validateObjectID(ObjectID ID) const
Checks that ID exists in the index.
LLVM_ABI Expected< std::optional< ObjectHandle > > load(ObjectID Ref)
LLVM_ABI std::unique_ptr< MemoryBuffer > getStandaloneMemoryBuffer(ObjectHandle Node, StringRef Name, bool RequiresNullTerminator) const
Get a MemoryBuffer for Node's data that stays valid after this database is destroyed.
LLVM_ABI Expected< bool > isMaterialized(ObjectID Ref)
Check whether the object associated with Ref is stored in the CAS.
LLVM_ABI Error validate(bool Deep, HashingFuncT Hasher) const
Validate the OnDiskGraphDB.
object_refs_range getObjectRefs(ObjectHandle Node) const
LLVM_ABI unsigned getHardStorageLimitUtilization() const
LLVM_ABI 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
LLVM_ABI FileBackedData getInternalFileBackedObjectData(ObjectHandle Node) const
Provides access to the underlying file path, that represents an object leaf node, when available.
LLVM_ABI Error storeFile(ObjectID ID, StringRef FilePath)
Associates the data of a file with a particular object ID.
LLVM_ABI size_t getStorageSize() const
static LLVM_ABI 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 ~OnDiskGraphDB()
LLVM_ABI 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 ArrayRef< char > getObjectData(ObjectHandle Node) const
LLVM_ABI 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.
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.
initializer< Ty > init(const Ty &Val)
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 an array ref of bytes from a string ref.
@ Unknown
Not known to have no common set bits.
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.
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 std::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.
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.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
void consumeError(Error Err)
Consume a Error without doing anything.
StringRef toStringRef(bool B)
Construct a string ref from a boolean.
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.
This class wraps the platform specific file handle/descriptor type to provide an unified representati...