LLVM 24.0.0git
PluginCAS.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// Implements \c ObjectStore and \c ActionCache on top of a dynamically loaded
11/// plugin that provides the C API in \c "llvm-c/CAS/PluginAPI_functions.h".
12///
13/// The asynchronous entry points of the plugin API are not called yet; they
14/// will be wired up once \c ObjectStore and \c ActionCache grow asynchronous
15/// interfaces.
16///
17//===----------------------------------------------------------------------===//
18
19#include "PluginAPI.h"
21#include "llvm/ADT/ScopeExit.h"
25#include "llvm/Support/Error.h"
27
28using namespace llvm;
29using namespace llvm::cas;
30
31namespace {
32
33class PluginCASContext : public CASContext {
34public:
35 void printIDImpl(raw_ostream &OS, const CASID &ID) const final;
36
37 StringRef getHashSchemaIdentifier() const final { return SchemaName; }
38
39 static Expected<std::shared_ptr<PluginCASContext>>
40 create(StringRef PluginPath, StringRef OnDiskPath,
41 ArrayRef<std::pair<std::string, std::string>> PluginArgs);
42
43 ~PluginCASContext() { Functions.cas_dispose(c_cas); }
44
45 llcas_functions_t Functions{};
46 llcas_cas_t c_cas = nullptr;
47 std::string SchemaName;
48
49 static Error errorAndDispose(char *c_err, const llcas_functions_t &Funcs) {
51 Funcs.string_dispose(c_err);
52 return E;
53 }
54
55 Error errorAndDispose(char *c_err) const {
56 return errorAndDispose(c_err, Functions);
57 }
58};
59
60} // anonymous namespace
61
62void PluginCASContext::printIDImpl(raw_ostream &OS, const CASID &ID) const {
63 ArrayRef<uint8_t> Hash = ID.getHash();
64 char *c_printed_id = nullptr;
65 char *c_err = nullptr;
66 if (Functions.digest_print(c_cas, llcas_digest_t{Hash.data(), Hash.size()},
67 &c_printed_id, &c_err))
68 report_fatal_error(errorAndDispose(c_err));
69 OS << c_printed_id;
70 Functions.string_dispose(c_printed_id);
71}
72
73/// Loads the plugin library at \p PluginPath and looks up its functions.
74static Expected<llcas_functions_t> loadPluginFunctions(StringRef PluginPath) {
75 auto reportError = [PluginPath](const Twine &Description) -> Error {
76 std::error_code EC = inconvertibleErrorCode();
77 return createStringError(EC, "error loading '" + PluginPath +
78 "': " + Description);
79 };
80
81 SmallString<256> PathBuf = PluginPath;
82 std::string ErrMsg;
83 sys::DynamicLibrary Lib =
85 if (!Lib.isValid())
86 return reportError(ErrMsg);
87
88 llcas_functions_t Functions{};
89
90#define CASPLUGINAPI_FUNCTION(name, required) \
91 if (!(Functions.name = (decltype(llcas_functions_t::name)) \
92 Lib.getAddressOfSymbol("llcas_" #name))) { \
93 if (required) \
94 return reportError("failed symbol 'llcas_" #name "' lookup"); \
95 }
96#include "PluginAPI_functions.def"
97#undef CASPLUGINAPI_FUNCTION
98
99 return Functions;
100}
101
102/// Creates a \c llcas_cas_options_t for \p OnDiskPath and \p PluginArgs. On
103/// success the caller is responsible for disposing it.
104static Expected<llcas_cas_options_t>
106 ArrayRef<std::pair<std::string, std::string>> PluginArgs) {
107 llcas_cas_options_t c_opts = Functions.cas_options_create();
108 Functions.cas_options_set_client_version(c_opts, LLCAS_VERSION_MAJOR,
110 SmallString<256> OnDiskPathBuf = OnDiskPath;
111 Functions.cas_options_set_ondisk_path(c_opts, OnDiskPathBuf.c_str());
112 for (const auto &Pair : PluginArgs) {
113 char *c_err = nullptr;
114 if (Functions.cas_options_set_option(c_opts, Pair.first.c_str(),
115 Pair.second.c_str(), &c_err)) {
116 Functions.cas_options_dispose(c_opts);
117 return PluginCASContext::errorAndDispose(c_err, Functions);
118 }
119 }
120 return c_opts;
121}
122
123Expected<std::shared_ptr<PluginCASContext>> PluginCASContext::create(
124 StringRef PluginPath, StringRef OnDiskPath,
125 ArrayRef<std::pair<std::string, std::string>> PluginArgs) {
126 llcas_functions_t Functions{};
127 if (Error E = loadPluginFunctions(PluginPath).moveInto(Functions))
128 return std::move(E);
129
130 llcas_cas_options_t c_opts = nullptr;
131 if (Error E = createPluginOptions(Functions, OnDiskPath, PluginArgs)
132 .moveInto(c_opts))
133 return std::move(E);
134 scope_exit DisposeOptions([&]() { Functions.cas_options_dispose(c_opts); });
135
136 char *c_err = nullptr;
137 llcas_cas_t c_cas = Functions.cas_create(c_opts, &c_err);
138 if (!c_cas)
139 return errorAndDispose(c_err, Functions);
140
141 char *c_schema = Functions.cas_get_hash_schema_name(c_cas);
142 std::string SchemaName = c_schema;
143 Functions.string_dispose(c_schema);
144
145 auto Ctx = std::make_shared<PluginCASContext>();
146 Ctx->Functions = Functions;
147 Ctx->c_cas = c_cas;
148 Ctx->SchemaName = std::move(SchemaName);
149 return Ctx;
150}
151
152//===----------------------------------------------------------------------===//
153// ObjectStore API
154//===----------------------------------------------------------------------===//
155
156namespace {
157
158class PluginObjectStore : public ObjectStore {
159public:
160 Expected<CASID> parseID(StringRef ID) final;
161 Expected<ObjectRef> store(ArrayRef<ObjectRef> Refs,
162 ArrayRef<char> Data) final;
163 Expected<ObjectRef> storeFromFile(StringRef Path) final;
164 Error exportDataToFile(ObjectHandle Node, StringRef Path) const final;
165 CASID getID(ObjectRef Ref) const final;
166 std::optional<ObjectRef> getReference(const CASID &ID) const final;
167 Expected<bool> isMaterialized(ObjectRef Ref) const final;
168 Expected<std::optional<ObjectHandle>> loadIfExists(ObjectRef Ref) final;
169 uint64_t getDataSize(ObjectHandle Node) const final;
170 Error forEachRef(ObjectHandle Node,
171 function_ref<Error(ObjectRef)> Callback) const final;
172 ObjectRef readRef(ObjectHandle Node, size_t I) const final;
173 size_t getNumRefs(ObjectHandle Node) const final;
174 ArrayRef<char> getData(ObjectHandle Node,
175 bool RequiresNullTerminator = false) const final;
176 std::unique_ptr<MemoryBuffer>
177 getStandaloneMemoryBufferImpl(ObjectHandle Node, StringRef Name,
178 bool RequiresNullTerminator) final;
179 Error validateObject(const CASID &ID) final {
180 // Not supported yet. Always return success.
181 return Error::success();
182 }
183
184 Error validate(bool CheckHash) const final;
185
186 Error setSizeLimit(std::optional<uint64_t> SizeLimit) final;
187 Expected<std::optional<uint64_t>> getStorageSize() const final;
188 Error pruneStorageData() final;
189
190 PluginObjectStore(std::shared_ptr<PluginCASContext>);
191
192 /// Exposes \c makeObjectRef to the file-local helpers below.
193 ObjectRef makeRef(uint64_t InternalRef) const {
194 return makeObjectRef(InternalRef);
195 }
196
197 std::shared_ptr<PluginCASContext> Ctx;
198};
199
200} // anonymous namespace
201
202Expected<CASID> PluginObjectStore::parseID(StringRef ID) {
203 // Use big enough stack so that we don't have to allocate in the heap.
204 SmallString<148> IDBuf(ID);
205 SmallVector<uint8_t, 68> BytesBuf(68);
206
207 auto parseDigest = [&]() -> Expected<unsigned> {
208 char *c_err = nullptr;
209 unsigned NumBytes = Ctx->Functions.digest_parse(
210 Ctx->c_cas, IDBuf.c_str(), BytesBuf.data(), BytesBuf.size(), &c_err);
211 if (NumBytes == 0)
212 return Ctx->errorAndDispose(c_err);
213 return NumBytes;
214 };
215
216 Expected<unsigned> NumBytes = parseDigest();
217 if (!NumBytes)
218 return NumBytes.takeError();
219
220 if (*NumBytes > BytesBuf.size()) {
221 BytesBuf.resize(*NumBytes);
222 NumBytes = parseDigest();
223 if (!NumBytes)
224 return NumBytes.takeError();
225 assert(*NumBytes == BytesBuf.size());
226 } else {
227 BytesBuf.truncate(*NumBytes);
228 }
229
230 return CASID::create(Ctx.get(), toStringRef(BytesBuf));
231}
232
233Expected<ObjectRef> PluginObjectStore::store(ArrayRef<ObjectRef> Refs,
234 ArrayRef<char> Data) {
236 c_ids.reserve(Refs.size());
237 for (ObjectRef Ref : Refs) {
238 c_ids.push_back(llcas_objectid_t{Ref.getInternalRef(*this)});
239 }
240
241 llcas_objectid_t c_stored_id;
242 char *c_err = nullptr;
243 if (Ctx->Functions.cas_store_object(
244 Ctx->c_cas, llcas_data_t{Data.data(), Data.size()}, c_ids.data(),
245 c_ids.size(), &c_stored_id, &c_err))
246 return Ctx->errorAndDispose(c_err);
247
248 return makeObjectRef(c_stored_id.opaque);
249}
250
251Expected<ObjectRef> PluginObjectStore::storeFromFile(StringRef Path) {
252 if (!Ctx->Functions.cas_store_from_filepath)
253 return ObjectStore::storeFromFile(Path);
254
255 llcas_objectid_t c_stored_id;
256 char *c_err = nullptr;
257 std::string PathStr = Path.str();
258 if (Ctx->Functions.cas_store_from_filepath(Ctx->c_cas, PathStr.c_str(),
259 &c_stored_id, &c_err))
260 return Ctx->errorAndDispose(c_err);
261
262 return makeObjectRef(c_stored_id.opaque);
263}
264
265Error PluginObjectStore::exportDataToFile(ObjectHandle Node,
266 StringRef Path) const {
267 if (!Ctx->Functions.loaded_object_export_data_to_filepath)
268 return ObjectStore::exportDataToFile(Node, Path);
269
270 char *c_err = nullptr;
271 std::string PathStr = Path.str();
272 if (Ctx->Functions.loaded_object_export_data_to_filepath(
273 Ctx->c_cas, llcas_loaded_object_t{Node.getInternalRef(*this)},
274 PathStr.c_str(), &c_err))
275 return Ctx->errorAndDispose(c_err);
276
277 return Error::success();
278}
279
281 return StringRef((const char *)c_digest.data, c_digest.size);
282}
283
284CASID PluginObjectStore::getID(ObjectRef Ref) const {
285 llcas_objectid_t c_id{Ref.getInternalRef(*this)};
286 llcas_digest_t c_digest =
287 Ctx->Functions.objectid_get_digest(Ctx->c_cas, c_id);
288 return CASID::create(Ctx.get(), toStringRef(c_digest));
289}
290
291std::optional<ObjectRef>
292PluginObjectStore::getReference(const CASID &ID) const {
293 ArrayRef<uint8_t> Hash = ID.getHash();
294 llcas_objectid_t c_id;
295 char *c_err = nullptr;
296 if (Ctx->Functions.cas_get_objectid(
297 Ctx->c_cas, llcas_digest_t{Hash.data(), Hash.size()}, &c_id, &c_err))
298 report_fatal_error(Ctx->errorAndDispose(c_err));
299
300 return makeObjectRef(c_id.opaque);
301}
302
303Expected<bool> PluginObjectStore::isMaterialized(ObjectRef Ref) const {
304 llcas_objectid_t c_id{Ref.getInternalRef(*this)};
305 char *c_err = nullptr;
306 llcas_lookup_result_t c_result = Ctx->Functions.cas_contains_object(
307 Ctx->c_cas, c_id, /*globally=*/false, &c_err);
308 switch (c_result) {
310 return true;
312 return false;
314 return Ctx->errorAndDispose(c_err);
315 }
316 llvm_unreachable("unknown llcas_lookup_result_t value");
317}
318
319Expected<std::optional<ObjectHandle>>
320PluginObjectStore::loadIfExists(ObjectRef Ref) {
321 llcas_objectid_t c_id{Ref.getInternalRef(*this)};
322 llcas_loaded_object_t c_obj;
323 char *c_err = nullptr;
324 llcas_lookup_result_t c_result =
325 Ctx->Functions.cas_load_object(Ctx->c_cas, c_id, &c_obj, &c_err);
326 switch (c_result) {
328 return makeObjectHandle(c_obj.opaque);
330 return std::nullopt;
332 return Ctx->errorAndDispose(c_err);
333 }
334 llvm_unreachable("unknown llcas_lookup_result_t value");
335}
336
337namespace {
338
339class ObjectRefsWrapper {
340public:
341 ObjectRefsWrapper(const ObjectHandle &Node, const PluginObjectStore &Store)
342 : Store(Store), Ctx(*Store.Ctx) {
343 llcas_loaded_object_t c_obj{Node.getInternalRef(Store)};
344 this->c_refs = Ctx.Functions.loaded_object_get_refs(Ctx.c_cas, c_obj);
345 }
346
347 size_t size() const {
348 return Ctx.Functions.object_refs_get_count(Ctx.c_cas, c_refs);
349 }
350
351 ObjectRef operator[](size_t I) const {
352 llcas_objectid_t c_id =
353 Ctx.Functions.object_refs_get_id(Ctx.c_cas, c_refs, I);
354 return Store.makeRef(c_id.opaque);
355 }
356
357private:
358 const PluginObjectStore &Store;
359 PluginCASContext &Ctx;
360 llcas_object_refs_t c_refs;
361};
362
363} // namespace
364
365// FIXME: Replace forEachRef/readRef/getNumRefs APIs with an iterator interface.
366Error PluginObjectStore::forEachRef(
367 ObjectHandle Node, function_ref<Error(ObjectRef)> Callback) const {
368 ObjectRefsWrapper Refs(Node, *this);
369 for (unsigned I = 0, E = Refs.size(); I != E; ++I) {
370 if (Error E = Callback(Refs[I]))
371 return E;
372 }
373 return Error::success();
374}
375
376ObjectRef PluginObjectStore::readRef(ObjectHandle Node, size_t I) const {
377 ObjectRefsWrapper Refs(Node, *this);
378 return Refs[I];
379}
380
381size_t PluginObjectStore::getNumRefs(ObjectHandle Node) const {
382 ObjectRefsWrapper Refs(Node, *this);
383 return Refs.size();
384}
385
386// FIXME: Remove getDataSize(ObjectHandle) from API requirement,
387// \c getData(ObjectHandle) should be enough.
388uint64_t PluginObjectStore::getDataSize(ObjectHandle Node) const {
389 ArrayRef<char> Data = getData(Node);
390 return Data.size();
391}
392
393ArrayRef<char> PluginObjectStore::getData(ObjectHandle Node,
394 bool RequiresNullTerminator) const {
395 // FIXME: Remove RequiresNullTerminator from ObjectStore API requirement?
396 // It is a requirement for the plugin API.
397 llcas_data_t c_data = Ctx->Functions.loaded_object_get_data(
398 Ctx->c_cas, llcas_loaded_object_t{Node.getInternalRef(*this)});
399 return ArrayRef((const char *)c_data.data, c_data.size);
400}
401
402namespace {
403/// A MemoryBuffer over a plugin's standalone buffer, which it releases when
404/// destroyed. It holds the dispose function directly rather than the
405/// \c llcas_cas_t, since the point of the buffer is to outlive that.
406class PluginStandaloneMemoryBuffer final : public MemoryBuffer {
407public:
408 using DisposeFn = void (*)(llcas_data_t);
409
410 PluginStandaloneMemoryBuffer(llcas_data_t Data, StringRef Name,
411 DisposeFn Dispose)
412 : Data(Data), Name(Name.str()), Dispose(Dispose) {
413 const char *Start = static_cast<const char *>(Data.data);
414 init(Start, Start + Data.size, /*RequiresNullTerminator=*/true);
415 }
416
417 ~PluginStandaloneMemoryBuffer() override { Dispose(Data); }
418
419 StringRef getBufferIdentifier() const final { return Name; }
420
421 BufferKind getBufferKind() const final { return MemoryBuffer_Malloc; }
422
423private:
424 llcas_data_t Data;
425 std::string Name;
426 DisposeFn Dispose;
427};
428} // namespace
429
430std::unique_ptr<MemoryBuffer> PluginObjectStore::getStandaloneMemoryBufferImpl(
431 ObjectHandle Node, StringRef Name, bool RequiresNullTerminator) {
432 // Both halves are needed: without the disposer there is no way to release
433 // what the getter hands out.
434 if (!Ctx->Functions.loaded_object_get_standalone_data ||
435 !Ctx->Functions.standalone_data_dispose)
437 RequiresNullTerminator);
438
439 llcas_data_t c_data = Ctx->Functions.loaded_object_get_standalone_data(
440 Ctx->c_cas, llcas_loaded_object_t{Node.getInternalRef(*this)});
441 if (!c_data.data)
443 RequiresNullTerminator);
444
445 return std::make_unique<PluginStandaloneMemoryBuffer>(
446 c_data, Name, Ctx->Functions.standalone_data_dispose);
447}
448
449Error PluginObjectStore::setSizeLimit(std::optional<uint64_t> SizeLimit) {
450 if (Ctx->Functions.cas_set_ondisk_size_limit) {
451 char *c_err = nullptr;
452 if (Ctx->Functions.cas_set_ondisk_size_limit(Ctx->c_cas,
453 SizeLimit.value_or(0), &c_err))
454 return Ctx->errorAndDispose(c_err);
455 }
456 return Error::success();
457}
458
459Expected<std::optional<uint64_t>> PluginObjectStore::getStorageSize() const {
460 if (!Ctx->Functions.cas_get_ondisk_size)
461 return std::nullopt;
462 char *c_err = nullptr;
463 int64_t ret = Ctx->Functions.cas_get_ondisk_size(Ctx->c_cas, &c_err);
464 switch (ret) {
465 case -1:
466 return std::nullopt;
467 case -2:
468 return Ctx->errorAndDispose(c_err);
469 default:
470 return ret;
471 }
472}
473
474Error PluginObjectStore::pruneStorageData() {
475 if (Ctx->Functions.cas_prune_ondisk_data) {
476 char *c_err = nullptr;
477 if (Ctx->Functions.cas_prune_ondisk_data(Ctx->c_cas, &c_err))
478 return Ctx->errorAndDispose(c_err);
479 }
480 return Error::success();
481}
482
483Error PluginObjectStore::validate(bool CheckHash) const {
484 if (Ctx->Functions.cas_validate) {
485 char *c_err = nullptr;
486 if (Ctx->Functions.cas_validate(Ctx->c_cas, CheckHash, &c_err))
487 return Ctx->errorAndDispose(c_err);
488 return Error::success();
489 }
490 return createStringError("plugin cas doesn't support validation");
491}
492
493PluginObjectStore::PluginObjectStore(std::shared_ptr<PluginCASContext> CASCtx)
494 : ObjectStore(*CASCtx), Ctx(std::move(CASCtx)) {}
495
496//===----------------------------------------------------------------------===//
497// ActionCache API
498//===----------------------------------------------------------------------===//
499
500namespace {
501
502class PluginActionCache : public ActionCache {
503public:
504 Expected<std::optional<CASID>> getImpl(ArrayRef<uint8_t> ResolvedKey,
505 bool CanBeDistributed) const final;
506
507 Error putImpl(ArrayRef<uint8_t> ResolvedKey, const CASID &Result,
508 bool CanBeDistributed) final;
509
510 PluginActionCache(std::shared_ptr<PluginCASContext>);
511
512 Error validate() const final;
513
514private:
515 std::shared_ptr<PluginCASContext> Ctx;
516};
517
518} // anonymous namespace
519
520Expected<std::optional<CASID>>
521PluginActionCache::getImpl(ArrayRef<uint8_t> ResolvedKey,
522 bool CanBeDistributed) const {
523 llcas_objectid_t c_value;
524 char *c_err = nullptr;
525 llcas_lookup_result_t c_result = Ctx->Functions.actioncache_get_for_digest(
526 Ctx->c_cas, llcas_digest_t{ResolvedKey.data(), ResolvedKey.size()},
527 &c_value, CanBeDistributed, &c_err);
528 switch (c_result) {
530 llcas_digest_t c_digest =
531 Ctx->Functions.objectid_get_digest(Ctx->c_cas, c_value);
532 return CASID::create(Ctx.get(), toStringRef(c_digest));
533 }
535 return std::nullopt;
537 return Ctx->errorAndDispose(c_err);
538 }
539 llvm_unreachable("unknown llcas_lookup_result_t value");
540}
541
542Error PluginActionCache::putImpl(ArrayRef<uint8_t> ResolvedKey,
543 const CASID &Result, bool CanBeDistributed) {
544 ArrayRef<uint8_t> Hash = Result.getHash();
545 llcas_objectid_t c_value;
546 char *c_err = nullptr;
547 if (Ctx->Functions.cas_get_objectid(Ctx->c_cas,
548 llcas_digest_t{Hash.data(), Hash.size()},
549 &c_value, &c_err))
550 return Ctx->errorAndDispose(c_err);
551
552 if (Ctx->Functions.actioncache_put_for_digest(
553 Ctx->c_cas, llcas_digest_t{ResolvedKey.data(), ResolvedKey.size()},
554 c_value, CanBeDistributed, &c_err))
555 return Ctx->errorAndDispose(c_err);
556
557 return Error::success();
558}
559
560PluginActionCache::PluginActionCache(std::shared_ptr<PluginCASContext> CASCtx)
561 : ActionCache(*CASCtx), Ctx(std::move(CASCtx)) {}
562
563Error PluginActionCache::validate() const {
564 if (Ctx->Functions.actioncache_validate) {
565 char *c_err = nullptr;
566 if (Ctx->Functions.actioncache_validate(Ctx->c_cas, &c_err))
567 return Ctx->errorAndDispose(c_err);
568 return Error::success();
569 }
570 return createStringError("plugin action cache doesn't support validation");
571}
572
573//===----------------------------------------------------------------------===//
574// createPluginCASDatabases API
575//===----------------------------------------------------------------------===//
576
577Expected<std::pair<std::shared_ptr<ObjectStore>, std::shared_ptr<ActionCache>>>
579 StringRef PluginPath, StringRef OnDiskPath,
580 ArrayRef<std::pair<std::string, std::string>> PluginArgs) {
581 std::shared_ptr<PluginCASContext> Ctx;
582 if (Error E = PluginCASContext::create(PluginPath, OnDiskPath, PluginArgs)
583 .moveInto(Ctx))
584 return std::move(E);
585 auto CAS = std::make_shared<PluginObjectStore>(Ctx);
586 auto AC = std::make_shared<PluginActionCache>(std::move(Ctx));
587 return std::make_pair(std::move(CAS), std::move(AC));
588}
589
590/// Loads the plugin and calls \p Fn with a \c llcas_cas_options_t for
591/// \p OnDiskPath and \p PluginArgs, converting the returned
592/// \c llcas_validation_result_t.
594 StringRef PluginPath, StringRef OnDiskPath,
595 ArrayRef<std::pair<std::string, std::string>> PluginArgs,
597 const llcas_functions_t &, llcas_cas_options_t, char **)>
598 Fn) {
599 llcas_functions_t Functions{};
600 if (Error E = loadPluginFunctions(PluginPath).moveInto(Functions))
601 return std::move(E);
602
603 llcas_cas_options_t c_opts = nullptr;
604 if (Error E = createPluginOptions(Functions, OnDiskPath, PluginArgs)
605 .moveInto(c_opts))
606 return std::move(E);
607 scope_exit DisposeOptions([&]() { Functions.cas_options_dispose(c_opts); });
608
609 char *c_err = nullptr;
611 if (Error E = Fn(Functions, c_opts, &c_err).moveInto(Result))
612 return std::move(E);
613 switch (Result) {
621 return PluginCASContext::errorAndDispose(c_err, Functions);
622 }
623 // The plugin is outside of our control, so an unknown result is an error
624 // rather than unreachable. Include the plugin's error message, if any.
625 std::string Msg;
627 OS << "unknown validation result " << static_cast<int>(Result) << " from '"
628 << PluginPath << "'";
629 if (c_err) {
630 OS << ": " << c_err;
631 Functions.string_dispose(c_err);
632 }
633 return createStringError(Msg);
634}
635
637 StringRef PluginPath, StringRef OnDiskPath,
638 ArrayRef<std::pair<std::string, std::string>> PluginArgs, bool CheckHash,
639 bool ForceValidation) {
641 PluginPath, OnDiskPath, PluginArgs,
642 [&](const llcas_functions_t &Functions, llcas_cas_options_t c_opts,
643 char **c_err) -> Expected<llcas_validation_result_t> {
644 if (!Functions.cas_validate_if_needed)
645 return createStringError(
646 "plugin cas doesn't support validate-if-needed");
647 return Functions.cas_validate_if_needed(c_opts, CheckHash,
648 ForceValidation, c_err);
649 });
650}
651
653 StringRef PluginPath, StringRef OnDiskPath,
654 ArrayRef<std::pair<std::string, std::string>> PluginArgs) {
656 PluginPath, OnDiskPath, PluginArgs,
657 [&](const llcas_functions_t &Functions, llcas_cas_options_t c_opts,
658 char **c_err) -> Expected<llcas_validation_result_t> {
659 if (!Functions.cas_recover_ondisk_data)
660 return createStringError("plugin cas doesn't support recovery");
661 return Functions.cas_recover_ondisk_data(c_opts, c_err);
662 });
663}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
unsigned uint64_t
This file contains the declaration of the ActionCache class, which is the base class for ActionCache ...
static Error reportError(StringRef Message)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static cl::opt< unsigned > SizeLimit("eif-limit", cl::init(6), cl::Hidden, cl::desc("Size limit in Hexagon early if-conversion"))
#define I(x, y, z)
Definition MD5.cpp:57
This file contains the declaration of the ObjectStore class.
Defines llcas_functions_t, the table of function pointers that is populated by looking up the llcas_*...
struct llcas_cas_options_s * llcas_cas_options_t
#define LLCAS_VERSION_MAJOR
struct llcas_cas_s * llcas_cas_t
#define LLCAS_VERSION_MINOR
llcas_validation_result_t
Return values for llcas_cas_validate_if_needed and llcas_cas_recover_ondisk_data.
@ LLCAS_VALIDATION_RESULT_SKIPPED
Validation or recovery was skipped, as it was not needed.
@ LLCAS_VALIDATION_RESULT_ERROR
An error occurred.
@ LLCAS_VALIDATION_RESULT_RECOVERED
The data was invalid, but was recovered.
@ LLCAS_VALIDATION_RESULT_VALID
The data is valid.
llcas_lookup_result_t
Return values for a load operation.
@ LLCAS_LOOKUP_RESULT_NOTFOUND
The object was not found.
@ LLCAS_LOOKUP_RESULT_SUCCESS
The object was found.
@ LLCAS_LOOKUP_RESULT_ERROR
An error occurred.
static Expected< ValidationResult > callPluginValidationFunction(StringRef PluginPath, StringRef OnDiskPath, ArrayRef< std::pair< std::string, std::string > > PluginArgs, function_ref< Expected< llcas_validation_result_t >(const llcas_functions_t &, llcas_cas_options_t, char **)> Fn)
Loads the plugin and calls Fn with a llcas_cas_options_t for OnDiskPath and PluginArgs,...
static Expected< llcas_cas_options_t > createPluginOptions(const llcas_functions_t &Functions, StringRef OnDiskPath, ArrayRef< std::pair< std::string, std::string > > PluginArgs)
Creates a llcas_cas_options_t for OnDiskPath and PluginArgs.
const char * Msg
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),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
const char * c_str()
void reserve(size_type N)
void push_back(const T &Elt)
pointer data()
Return a pointer to the vector's buffer, even if empty().
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
A cache from a key (that describes an action) to the result of performing that action.
Definition ActionCache.h:49
Context for CAS identifiers.
Definition CASID.h:28
Unique identifier for a CAS object.
Definition CASID.h:58
static CASID create(const CASContext *Context, StringRef Hash)
Create CASID from CASContext and raw hash bytes.
Definition CASID.h:117
virtual std::unique_ptr< MemoryBuffer > getStandaloneMemoryBufferImpl(ObjectHandle Node, StringRef Name, bool RequiresNullTerminator)
Customization point for getStandaloneMemoryBuffer().
virtual Error exportDataToFile(ObjectHandle Node, StringRef Path) const
Exports the data of an object to a file path.
virtual Expected< ObjectRef > storeFromFile(StringRef Path)
Stores the data of a file into ObjectStore.
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.
Definition raw_ostream.h:53
A raw_ostream that writes to an std::string.
static LLVM_ABI DynamicLibrary getPermanentLibrary(const char *filename, std::string *errMsg=nullptr)
This function permanently loads the dynamic library at the given path using the library load operatio...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void validate(const Triple &TT, const FeatureBitset &FeatureBits)
@ Valid
The data is already valid.
@ Recovered
The data was invalid, but was recovered.
@ Skipped
Validation or recovery was skipped, as it was not needed.
LLVM_ABI Expected< ValidationResult > validatePluginCASDatabasesIfNeeded(StringRef PluginPath, StringRef OnDiskPath, ArrayRef< std::pair< std::string, std::string > > PluginArgs, bool CheckHash, bool ForceValidation)
Validate the on-disk data of a plugin-backed CAS in-process if needed, by calling the plugin's llcas_...
LLVM_ABI Expected< std::pair< std::shared_ptr< ObjectStore >, std::shared_ptr< ActionCache > > > createPluginCASDatabases(StringRef PluginPath, StringRef OnDiskPath, ArrayRef< std::pair< std::string, std::string > > PluginArgs)
Create ObjectStore and ActionCache instances backed by a plugin that implements the C API in "llvm-c/...
LLVM_ABI Expected< ValidationResult > recoverPluginCASDatabases(StringRef PluginPath, StringRef OnDiskPath, ArrayRef< std::pair< std::string, std::string > > PluginArgs)
Recover the on-disk data of a plugin-backed CAS after a failed validatePluginCASDatabasesIfNeeded,...
initializer< Ty > init(const Ty &Val)
uint64_t getDataSize(const FuncRecordTy *Record)
Return the coverage map data size for the function.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition Transport.h:132
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
This is an optimization pass for GlobalISel generic memory operations.
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.
Definition STLExtras.h:1685
scope_exit(Callable) -> scope_exit< Callable >
@ Store
The extracted value is stored (ExtractElement only).
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:94
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
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.
Definition ModRef.h:32
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1933
StringRef toStringRef(bool B)
Construct a string ref from a boolean.
const void * data
Digest hash bytes.
const uint8_t * data
See documentation in "llvm-c/CAS/PluginAPI_functions.h" for how these functions are used.
Definition PluginAPI.h:22
void(* string_dispose)(char *)
Definition PluginAPI.h:25
size_t(* object_refs_get_count)(llcas_cas_t, llcas_object_refs_t)
Definition PluginAPI.h:103
bool(* digest_print)(llcas_cas_t, llcas_digest_t, char **printed_id, char **error)
Definition PluginAPI.h:66
llcas_object_refs_t(* loaded_object_get_refs)(llcas_cas_t, llcas_loaded_object_t)
Definition PluginAPI.h:95
llcas_cas_t(* cas_create)(llcas_cas_options_t, char **error)
Definition PluginAPI.h:43
char *(* cas_get_hash_schema_name)(llcas_cas_t)
Definition PluginAPI.h:69
void(* cas_options_dispose)(llcas_cas_options_t)
Definition PluginAPI.h:33
llcas_objectid_t(* object_refs_get_id)(llcas_cas_t, llcas_object_refs_t, size_t index)
Definition PluginAPI.h:105