Skip to content

Commit 4066cfb

Browse files
MichaelCuevasfacebook-github-bot
authored andcommitted
getAttributesFromFilesV2: support requesting blake3 for trees
Summary: # Context The new AugmentedManifest format used by Sapling and Mononoke will support looking up Trees/Blobs from CAS via (Blake3,size) pairs. We already provide a way for users to get (Blake3,size) pairs for blobs, but there is currently no easy way to get this information for trees. We want to add support to getAttributesFromFilesV2 for looking up the (Blake3,size) pairs for trees as well. To do this, we'll need to add a method for querying TreeMetadata (including size and Blake3 hashes) via the SaplingBackingStore. This initial implementation of TreeMetadata will only include the following features: 1) Ability to query TreeMetadata from the SaplingBackingStore via a getTreeMetadata endpoint 2) The ability to request TreeMetadata from the getAttributesFromFilesV2 thrift endpoint In the future, we will extend the implementation to support: 1) Automatically fetching TreeMetadata during BackingStore::getTree requests 2) Caching TreeMetadata in Eden's in-memory caches # This diff This diff finally implements the logic for requesting blake3 hashes from getAttributesFromFilesV2. Reviewed By: kmancini Differential Revision: D58594553 fbshipit-source-id: 054a39f13d606a81db915b4d616a2f4d19d34760
1 parent 41e6f47 commit 4066cfb

4 files changed

Lines changed: 214 additions & 61 deletions

File tree

eden/fs/inodes/VirtualInode.cpp

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "eden/fs/inodes/InodeError.h"
1414
#include "eden/fs/inodes/TreeInode.h"
1515
#include "eden/fs/model/Tree.h"
16+
#include "eden/fs/model/TreeMetadata.h"
1617
#include "eden/fs/service/gen-cpp2/eden_types.h"
1718
#include "eden/fs/store/ObjectStore.h"
1819

@@ -215,9 +216,11 @@ ImmediateFuture<BlobMetadata> VirtualInode::getBlobMetadata(
215216
});
216217
}
217218

218-
EntryAttributes VirtualInode::getEntryAttributesForNonFile(
219+
ImmediateFuture<EntryAttributes> VirtualInode::getEntryAttributesForNonFile(
219220
EntryAttributeFlags requestedAttributes,
220221
RelativePathPiece path,
222+
const std::shared_ptr<ObjectStore>& objectStore,
223+
const ObjectFetchContextPtr& fetchContext,
221224
std::optional<TreeEntryType> entryType,
222225
int errorCode,
223226
std::string additionalErrorContext) const {
@@ -227,26 +230,91 @@ EntryAttributes VirtualInode::getEntryAttributesForNonFile(
227230
folly::Try<Hash20>{PathError{errorCode, path, additionalErrorContext}};
228231
}
229232

230-
std::optional<folly::Try<Hash32>> blake3;
231-
if (requestedAttributes.contains(ENTRY_ATTRIBUTE_BLAKE3)) {
232-
blake3 =
233-
folly::Try<Hash32>{PathError{errorCode, path, additionalErrorContext}};
234-
}
235-
236-
std::optional<folly::Try<uint64_t>> size;
237-
if (requestedAttributes.contains(ENTRY_ATTRIBUTE_SIZE)) {
238-
size = folly::Try<uint64_t>{
239-
PathError{errorCode, path, std::move(additionalErrorContext)}};
240-
}
241-
242233
std::optional<folly::Try<std::optional<TreeEntryType>>> type;
243234
if (requestedAttributes.contains(ENTRY_ATTRIBUTE_SOURCE_CONTROL_TYPE)) {
244235
type = folly::Try<std::optional<TreeEntryType>>{entryType};
245236
}
246237

247238
std::optional<folly::Try<std::optional<ObjectId>>> objectId;
239+
auto oid = getObjectId();
248240
if (requestedAttributes.contains(ENTRY_ATTRIBUTE_OBJECT_ID)) {
249-
objectId = folly::Try<std::optional<ObjectId>>{getObjectId()};
241+
objectId = folly::Try<std::optional<ObjectId>>{oid};
242+
}
243+
244+
std::optional<folly::Try<Hash32>> blake3;
245+
std::optional<folly::Try<uint64_t>> size;
246+
247+
// The entry is a symlink, socket, or other unsupported type. We return
248+
// error values for these entry types if they were requested.
249+
//
250+
// entryType is std::nullopt if the entry is a socket or other non-scm type
251+
if (entryType.value_or(TreeEntryType::SYMLINK) != TreeEntryType::TREE) {
252+
if (requestedAttributes.contains(ENTRY_ATTRIBUTE_SIZE)) {
253+
size = folly::Try<uint64_t>{
254+
PathError{errorCode, path, additionalErrorContext}};
255+
}
256+
257+
if (requestedAttributes.contains(ENTRY_ATTRIBUTE_BLAKE3)) {
258+
blake3 = folly::Try<Hash32>{
259+
PathError{errorCode, path, std::move(additionalErrorContext)}};
260+
}
261+
} else {
262+
// The entry is a tree, and therefore we can attempt to compute tree
263+
// metadata for it. However, we can only compute the additional attributes
264+
// of trees that have ObjectIds. In other words, the tree must be
265+
// unmaterialized.
266+
if ((requestedAttributes.contains(ENTRY_ATTRIBUTE_BLAKE3) ||
267+
requestedAttributes.contains(ENTRY_ATTRIBUTE_SIZE)) &&
268+
oid.has_value()) {
269+
auto treeMetaFut =
270+
objectStore->getTreeMetadata(oid.value(), fetchContext)
271+
.thenValue(
272+
[requestedAttributes, sha1, type, objectId, blake3, size](
273+
TreeMetadata treeMeta) mutable {
274+
if (requestedAttributes.contains(ENTRY_ATTRIBUTE_BLAKE3)) {
275+
blake3 =
276+
std::optional<folly::Try<Hash32>>{treeMeta.blake3};
277+
}
278+
if (requestedAttributes.contains(ENTRY_ATTRIBUTE_SIZE)) {
279+
size = std::optional<folly::Try<uint64_t>>{
280+
std::move(treeMeta.size)};
281+
}
282+
return EntryAttributes{
283+
std::move(sha1),
284+
std::move(blake3),
285+
std::move(size),
286+
std::move(type),
287+
std::move(objectId)};
288+
});
289+
return std::move(treeMetaFut)
290+
.thenError([requestedAttributes,
291+
treeSha1 = std::move(sha1),
292+
treeType = std::move(type),
293+
treeObjectId = std::move(objectId),
294+
treeBlake3 = std::move(blake3),
295+
treeSize = std::move(size)](
296+
const folly::exception_wrapper& ex) mutable {
297+
// We failed to get tree aux data. This shouldn't cause the
298+
// entire result to be an error. We can return whichever
299+
// attributes we successfully fetched.
300+
if (requestedAttributes.contains(ENTRY_ATTRIBUTE_BLAKE3)) {
301+
treeBlake3 = folly::Try<Hash32>{ex};
302+
}
303+
304+
if (requestedAttributes.contains(ENTRY_ATTRIBUTE_SIZE)) {
305+
treeSize = folly::Try<uint64_t>{ex};
306+
}
307+
308+
return EntryAttributes{
309+
std::move(treeSha1),
310+
std::move(treeBlake3),
311+
std::move(treeSize),
312+
std::move(treeType),
313+
std::move(treeObjectId),
314+
};
315+
});
316+
}
317+
// We return empty tree metadata attributes for materialized directories
250318
}
251319

252320
return EntryAttributes{
@@ -271,18 +339,27 @@ ImmediateFuture<EntryAttributes> VirtualInode::getEntryAttributes(
271339
break;
272340
case dtype_t::Dir:
273341
return getEntryAttributesForNonFile(
274-
requestedAttributes, path, TreeEntryType::TREE, EISDIR);
342+
requestedAttributes,
343+
path,
344+
objectStore,
345+
fetchContext,
346+
TreeEntryType::TREE,
347+
EISDIR);
275348
case dtype_t::Symlink:
276349
return getEntryAttributesForNonFile(
277350
requestedAttributes,
278351
path,
352+
objectStore,
353+
fetchContext,
279354
TreeEntryType::SYMLINK,
280355
EINVAL,
281356
"file is a symlink");
282357
default:
283358
return getEntryAttributesForNonFile(
284359
requestedAttributes,
285360
path,
361+
objectStore,
362+
fetchContext,
286363
std::nullopt,
287364
EINVAL,
288365
fmt::format(

eden/fs/inodes/VirtualInode.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,11 @@ class VirtualInode {
188188
const ObjectFetchContextPtr& fetchContext,
189189
bool blake3Required = false) const;
190190

191-
EntryAttributes getEntryAttributesForNonFile(
191+
ImmediateFuture<EntryAttributes> getEntryAttributesForNonFile(
192192
EntryAttributeFlags requestedAttributes,
193193
RelativePathPiece path,
194+
const std::shared_ptr<ObjectStore>& objectStore,
195+
const ObjectFetchContextPtr& fetchContext,
194196
std::optional<TreeEntryType> entryType,
195197
int errorCode,
196198
std::string additionalErrorContext = {}) const;

eden/fs/inodes/test/VirtualInodeTest.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,13 @@ TEST(VirtualInodeTest, fileOpsOnCorrectObjectsOnly) {
846846
if (metadataTry.hasValue()) {
847847
auto& metadata = metadataTry.value();
848848
EXPECT_TRUE(metadata.sha1.value().hasException());
849-
EXPECT_TRUE(metadata.size.value().hasException());
849+
if (info.isMaterialized()) {
850+
// We can't get the size/blake3 of materialized directory
851+
EXPECT_FALSE(metadata.size.has_value());
852+
} else {
853+
// We require a remote lookup to get the size/blake3 of directories
854+
EXPECT_TRUE(metadata.size.value().hasException());
855+
}
850856
EXPECT_EQ(metadata.type.value().value(), info.getTreeEntryType())
851857
<< " on path " << info.getLogPath();
852858
}
@@ -878,7 +884,13 @@ TEST(VirtualInodeTest, fileOpsOnCorrectObjectsOnly) {
878884
if (metadataTry.hasValue()) {
879885
auto& metadata = metadataTry.value();
880886
EXPECT_FALSE(metadata.sha1.has_value());
881-
EXPECT_TRUE(metadata.size.value().hasException());
887+
if (info.isMaterialized()) {
888+
// We can't get the size/blake3 of materialized directory
889+
EXPECT_FALSE(metadata.size.has_value());
890+
} else {
891+
// We require a remote lookup to get the size/blake3 of directories
892+
EXPECT_TRUE(metadata.size.value().hasException());
893+
}
882894
EXPECT_EQ(metadata.type.value().value(), info.getTreeEntryType())
883895
<< " on path " << info.getLogPath();
884896
}

0 commit comments

Comments
 (0)