Skip to content

Commit

Permalink
DAOS-16924 dfs: new readdir API
Browse files Browse the repository at this point in the history
Add a new DFS readdir API that utilizes a new DFS anchor object which
can be updated to include caching parameters for future calls. This API
will be more useful when client side caching for readdir is implemented
to access buckets of readdir entries.

Required-githooks: true

Signed-off-by: Mohamad Chaarawi <[email protected]>
  • Loading branch information
mchaarawi committed Jan 8, 2025
1 parent 944a348 commit cc3cadb
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 63 deletions.
6 changes: 5 additions & 1 deletion src/client/dfs/dcache.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/**
* (C) Copyright 2022-2024 Intel Corporation.
* (C) Copyright 2025 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
Expand Down Expand Up @@ -75,7 +76,7 @@ typedef void (*drec_decref_fn_t)(dfs_dcache_t *, dfs_obj_t *);
typedef void (*drec_del_at_fn_t)(dfs_dcache_t *, dfs_obj_t *);
typedef int (*drec_del_fn_t)(dfs_dcache_t *, char *, dfs_obj_t *);

/** DFS directory cache */
/** DFS dentry cache */
struct dfs_dcache {
/** Cached DAOS file system */
dfs_t *dd_dfs;
Expand Down Expand Up @@ -990,3 +991,6 @@ drec_del(dfs_dcache_t *dcache, char *path, dfs_obj_t *parent)

return dcache->drec_del_fn(dcache, path, parent);
}

// dcache_readdir(dfs_dcache_t *dcache, dfs_obj_t *obj, dfs_dir_anchor_t *anchor, struct dirent dir)
// {}
10 changes: 10 additions & 0 deletions src/client/dfs/dfs_internal.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/**
* (C) Copyright 2019-2024 Intel Corporation.
* (C) Copyright 2025 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
Expand Down Expand Up @@ -274,6 +275,15 @@ struct dfs_mnt_hdls {
int type;
};

/** readdir anchor for dfs_readdir2(). If dcache is disabled, the only valid setting is the
* daos_anchor_t. */
struct dfs_dir_anchor {
dfs_obj_t *dda_dir;
daos_anchor_t dda_anchor_int;
size_t dda_bucket_id;
off_t dda_bucket_offset;
};

static inline bool
tspec_gt(struct timespec l, struct timespec r)
{
Expand Down
74 changes: 74 additions & 0 deletions src/client/dfs/readdir.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/**
* (C) Copyright 2018-2024 Intel Corporation.
* (C) Copyright 2025 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
Expand All @@ -9,6 +10,7 @@
#define D_LOGFAC DD_FAC(dfs)

#include <daos/common.h>
#include <daos/object.h>

#include "dfs_internal.h"

Expand Down Expand Up @@ -113,6 +115,78 @@ dfs_readdirplus(dfs_t *dfs, dfs_obj_t *obj, daos_anchor_t *anchor, uint32_t *nr,
return readdir_int(dfs, obj, anchor, nr, dirs, stbufs);
}

int
dfs_dir_anchor_init(dfs_obj_t *obj, dfs_dir_anchor_t **_anchor)
{
dfs_dir_anchor_t *anchor;

if (obj == NULL || !S_ISDIR(obj->mode))
return ENOTDIR;

D_ALLOC_PTR(anchor);
if (anchor == NULL)
return ENOMEM;

anchor->dda_dir = obj;
daos_anchor_init(&anchor->dda_anchor_int, 0);
anchor->dda_bucket_id = 0;
anchor->dda_bucket_offset = 0;
*_anchor = anchor;
return 0;
}

void
dfs_dir_anchor_reset(dfs_dir_anchor_t *anchor)
{
daos_anchor_init(&anchor->dda_anchor_int, 0);
anchor->dda_bucket_id = 0;
anchor->dda_bucket_offset = 0;
}

bool
dfs_dir_anchor_is_eof(dfs_dir_anchor_t *anchor)
{
return daos_anchor_is_eof(&anchor->dda_anchor_int);
}

void
dfs_dir_anchor_destroy(dfs_dir_anchor_t *anchor)
{
D_FREE(anchor);
}

int
dfs_readdir_s(dfs_t *dfs, dfs_obj_t *dir, dfs_dir_anchor_t *anchor, struct dirent *entry)
{
uint32_t nr = 1;
int rc;

if (daos_oid_cmp(dir->oid, anchor->dda_dir->oid) != 0)
return EINVAL;
if (daos_anchor_is_eof(&anchor->dda_anchor_int))
return -1;

rc = readdir_int(dfs, dir, &anchor->dda_anchor_int, &nr, entry, NULL);
if (rc)
return rc;

/** if we did not enumerate anything, try again to make sure we hit EOF */
if (nr == 0) {
if (daos_anchor_is_eof(&anchor->dda_anchor_int))
return -1; /** typically EOF code */
else
return EIO;
}
return rc;
#if 0
/** if no caching, just use the internal anchor with 1 entry */
if (dfs->dcache == NULL)
return readdir_int(dfs, obj, &anchor->dda_anchor_int, 1, &dir, NULL);
else
dcache_readdir(dfs->dcache, obj, anchor, dir);
#endif
}

int
dfs_iterate(dfs_t *dfs, dfs_obj_t *obj, daos_anchor_t *anchor, uint32_t *nr, size_t size,
dfs_filler_cb_t op, void *udata)
Expand Down
73 changes: 73 additions & 0 deletions src/include/daos_fs.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* (C) Copyright 2018-2024 Intel Corporation.
* (C) Copyright 2025 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
Expand Down Expand Up @@ -47,6 +48,8 @@ extern "C" {
typedef struct dfs_obj dfs_obj_t;
/** DFS mount handle struct */
typedef struct dfs dfs_t;
/** DFS readdir anchor for dfs_readdir_s() */
typedef struct dfs_dir_anchor dfs_dir_anchor_t;

/*
* Consistency modes of the DFS container. A container created with balanced
Expand Down Expand Up @@ -741,6 +744,76 @@ int
dfs_readdirplus(dfs_t *dfs, dfs_obj_t *obj, daos_anchor_t *anchor, uint32_t *nr,
struct dirent *dirs, struct stat *stbufs);

/**
* Initialize a readdir anchor for dfs_readdir_s().
*
* \param[in] dir Opened directory object for readdir.
* \param[out] anchor Pointer to initialized anchor. This muse be freed with
* dfs_dir_anchor_destroy().
*
* \return 0 on success, errno code on failure.
*/
int
dfs_dir_anchor_init(dfs_obj_t *dir, dfs_dir_anchor_t **anchor);

/**
* Reset an anchor the beginning of dir stream.
*
* \param[in] anchor anchor to reset
*
*/
void
dfs_dir_anchor_reset(dfs_dir_anchor_t *anchor);

/**
* check if the anchor is at EOF.
*
* \param[in] anchor anchor to check
*
* \return true if anchor is at EOF, false otherwise.
*/
bool
dfs_dir_anchor_is_eof(dfs_dir_anchor_t *anchor);

/**
* Destroy/free a DFS readdir anchor.
*
* \param[in] anchor anchor to free
*
*/
void
dfs_dir_anchor_destroy(dfs_dir_anchor_t *anchor);

/**
* Directory readdir that just returns the next entry in the directory anchor stream. The stream is
* actually determined by the anchor which can be reset at anytime to start from the beginning. For
* every call of this function with the anchor, it returns 0 with the d_name of the dirent struct
* populated for the next entry. The function returns -1 if it reaches the end of stream and sets
* anchor to EOF. It is possible to get the last entry in the stream and the anchor being set to EOF
* in that call. It is also possible to get the last entry in the stream and the anchor still not
* set to EOF in that readdir call. In both situations the return code of the readdir call is 0
* (success) and the entry is valid and should be consumed. In the latter case, the caller does not
* know that we reached the end of the directory and should make another readdir call. The next call
* in both scenarios will return -1 and the anchor will be set to EOF in that call. Further calls
* will behave similarly until the anchor is reset to the beginning.
*
* If caching is enabled on this dfs mount, this readdir call will utilize the readdir cache and may
* pull in an entire bucket of entries at once if the current stream is not in the cache.
*
* \param[in] dfs Pointer to the mounted file system.
* \param[in] obj Opened directory object.
* \param[in,out]
* anchor Anchor for the next call, it should initialized before first use.
* \param[out] dir returned dirent. Unlike the libc call, this dirent pointer is provided by
* the caller and not an internal pointer.
*
* \return 0 on success
* -1 on end of dir stream (no more entries to enumerate)
* errno code on failure
*/
int
dfs_readdir_s(dfs_t *dfs, dfs_obj_t *obj, dfs_dir_anchor_t *anchor, struct dirent *dir);

/**
* User callback defined for dfs_readdir_size.
*/
Expand Down
Loading

0 comments on commit cc3cadb

Please sign in to comment.