[Ocfs2-test-devel] [PATCH 3/4] Ocfs2-test: Add generic dir operation funcs for libocfs2test.

Sunil Mushran sunil.mushran at oracle.com
Wed Apr 1 19:34:26 PDT 2009


tristan.ye wrote:
> Actually the following dir operation funcs also copied from mark's
> inline-dirs test:-)
>
> Yes, I do agree with you on the point a list can save space when
> unlinking compared to array during tests. but we also will be losing the
> efficiency on random dir access, such as a random read, unlink and entry
> find etc. Actaully, such random operations against dirents appears
> everywhere during a dir related tests. I'm thinking if a list scheme
> will bring us a obivious penality when the dirents number was
> tremendous.
>
> In fact a tests with a scale of 40000 entries take us 10M physical
> memory, it's acceptable during the tests. but it does bring us the
> efficiency on random access in return.
>
> How do you think about it?
>   

Yes, list will not work. My concern is not about the amount
of memory used as much as it is with it wasted. In the current
scheme, if one adds files and deletes them, one will still run out
of space. And considering this is a library, one has to be careful
because you are in effect inviting future developers to use (and
misuse) this lib.

How about in unlink instead of zeroing out the entry we replace
it with the last entry in the array and decrement num_dirents.

Will that work?

BTW, do you have a sample usage of the library. I want to see
how you plan to use it.


>> Tristan Ye wrote:
>>     
>>> Provide generic utility fuctions on dir operations for ocfs2-tests.
>>>
>>> Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
>>> ---
>>>  programs/libocfs2test/dir_ops.c |  345 +++++++++++++++++++++++++++++++++++++++
>>>  programs/libocfs2test/dir_ops.h |   85 ++++++++++
>>>  2 files changed, 430 insertions(+), 0 deletions(-)
>>>  create mode 100644 programs/libocfs2test/dir_ops.c
>>>  create mode 100644 programs/libocfs2test/dir_ops.h
>>>
>>> diff --git a/programs/libocfs2test/dir_ops.c b/programs/libocfs2test/dir_ops.c
>>> new file mode 100644
>>> index 0000000..5857231
>>> --- /dev/null
>>> +++ b/programs/libocfs2test/dir_ops.c
>>> @@ -0,0 +1,345 @@
>>> +/* -*- mode: c; c-basic-offset: 8; -*-
>>> + * vim: noexpandtab sw=8 ts=8 sts=0:
>>> + *
>>> + * dir_ops.c
>>> + *
>>> + * Provide generic utility fuctions on dir operations for ocfs2-tests
>>> + *
>>> + * Copyright (C) 2008 Oracle.  All rights reserved.
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU General Public
>>> + * License version 2 as published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + * General Public License for more details.
>>> + */
>>> +
>>> +#include "dir_ops.h"
>>> +
>>> +extern unsigned long num_dirents;
>>> +extern struct my_dirent *dirents;
>>> +
>>> +extern int is_dot_entry(struct my_dirent *dirent)
>>> +{
>>> +	if (dirent->name_len == 1 && dirent->name[0] == '.')
>>> +		return 1;
>>> +	if (dirent->name_len == 2 && dirent->name[0] == '.'
>>> +	    && dirent->name[1] == '.')
>>> +		return 1;
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +extern int unlink_dirent(char *dirname, struct my_dirent *dirent)
>>> +{
>>> +	char path[PATH_MAX];
>>> +
>>> +	dirent->name_len = 0;
>>> +	dirent->seen = 0;
>>> +	sprintf(path, "%s/%s", dirname, dirent->name);
>>> +
>>> +	return unlink(path);
>>> +}
>>> +
>>> +extern int create_and_prep_dir(char *dirname)
>>> +{
>>> +	int ret;
>>> +	struct my_dirent *dirent;
>>> +	
>>> +	memset(dirents, 0, sizeof(struct my_dirent) * MAX_DIRENTS);
>>> +	
>>> +	dirent = &dirents[0];
>>> +	dirent->type = S_IFDIR >> S_SHIFT;
>>> +	dirent->name_len = 1;
>>> +	strcpy(dirent->name, ".");
>>> +	
>>> +	dirent = &dirents[1];
>>> +	dirent->type = S_IFDIR >> S_SHIFT;
>>> +	dirent->name_len = 2;
>>> +	strcpy(dirent->name, "..");
>>> +	
>>> +	num_dirents = 2;
>>> +	ret = mkdir(dirname, FILE_MODE);
>>> +	if (ret) {
>>> +	        ret = errno;
>>> +	        fprintf(stderr, "mkdir failure %d: %s\n", ret, strerror(ret));
>>> +		return ret;
>>> +	}
>>> +	
>>> +	return 0;
>>> +}
>>> +
>>> +extern int destroy_dir(char *dirname)
>>> +{
>>> +	int ret, i;
>>> +	struct my_dirent *dirent;
>>> +
>>> +	for (i = 0; i < num_dirents; i++) {
>>> +		dirent = &dirents[i];
>>> +
>>> +		if (dirent->name_len == 0)
>>> +			continue;
>>> +
>>> +		if (!is_dot_entry(dirent)) {
>>> +			ret = unlink_dirent(dirname, dirent);
>>> +			if (ret < 0) {
>>> +				ret = errno;
>>> +				fprintf(stderr, "unlink failure %d: %s\n", ret,
>>> +					strerror(ret));
>>> +				return ret;
>>> +			}
>>> +
>>> +			dirent->name_len = 0;
>>> +		}
>>> +
>>> +        }
>>> +
>>> +	ret = rmdir(dirname);
>>> +	if (ret) {
>>> +		ret = errno;
>>> +		fprintf(stderr, "rmdir failure %d: %s\n", ret,
>>> +			strerror(ret));
>>> +		return ret;
>>> +	}
>>> +	
>>> +	num_dirents = 0;
>>> +	
>>> +	return 0;
>>> +}
>>> +
>>> +extern struct my_dirent *find_my_dirent(char *name)
>>> +{
>>> +	int i, len;
>>> +	struct my_dirent *my_dirent;
>>> +
>>> +	len = strlen(name);
>>> +
>>> +	for (i = 0; i < num_dirents; i++) {
>>> +		my_dirent = &dirents[i];
>>> +
>>> +		if (my_dirent->name_len == 0)
>>> +			continue;
>>> +
>>> +		if (my_dirent->name_len == len &&
>>> +		    strcmp(my_dirent->name, name) == 0)
>>> +			return my_dirent;
>>> +	}
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +
>>> +extern int create_file(char *filename, char *dirname)
>>> +{
>>> +	int ret, fd;
>>> +	struct my_dirent *dirent;
>>> +	char path[PATH_MAX];
>>> +	
>>> +	dirent = &dirents[num_dirents];
>>> +	num_dirents++;
>>> +	
>>> +	dirent->type = S_IFREG >> S_SHIFT;
>>> +	dirent->name_len = strlen(filename);
>>> +	dirent->seen = 0;
>>> +	strcpy(dirent->name, filename);
>>> +	
>>> +	sprintf(path, "%s/%s", dirname, dirent->name);
>>> +	
>>> +	fd = open(path, FILE_BUFFERED_RW_FLAGS, FILE_MODE);
>>> +	if (fd < 0) {
>>> +	        ret = errno;
>>> +	        fprintf(stderr, "Create file %s failure %d: %s\n", path, ret,
>>> +			strerror(ret));
>>> +		return ret;
>>> +	}
>>> +	
>>> +	close(fd);
>>> +	
>>> +	return 0;
>>> +}
>>> +
>>> +extern int create_files(char *prefix, unsigned long num, char *dirname)
>>> +{
>>> +        int i, ret;
>>> +	char dirent_nam[OCFS2_MAX_FILENAME_LEN];
>>> +	char path[PATH_MAX];
>>> +
>>> +        for (i = 0; i < num; i++) {
>>> +		if (!prefix) {
>>> +			get_rand_nam(dirent_nam, 3, OCFS2_MAX_FILENAME_LEN/4);
>>> +			ret = create_file(dirent_nam, dirname);
>>> +		} else {
>>> +                	snprintf(path, PATH_MAX, "%s%011d", prefix, i);
>>> +			ret = create_file(path, dirname);
>>> +		}
>>> +
>>> +		if (ret < 0)
>>> +			return ret;
>>> +        }
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +extern int is_dir_empty(char *name)
>>> +{
>>> +	DIR *dir;
>>> +	int ret, entries = 0;
>>> +	struct dirent *dirent;
>>> +	
>>> +	dir = opendir(name);
>>> +	if (dir < 0) {
>>> +		ret = errno;
>>> +		fprintf(stderr, "dir open failure %d: %s\n", ret,
>>> +			strerror(ret));
>>> +	}
>>> +
>>> +	dirent = readdir(dir);
>>> +	while (dirent) {
>>> +		entries++;
>>> +		dirent = readdir(dir);
>>> +		if ( entries > 2)
>>> +			break;
>>> +	}
>>> +
>>> +	closedir(dir);
>>> +
>>> +	if (entries == 2)
>>> +		return 1;
>>> +	else
>>> +		return 0;
>>> +}
>>> +
>>> +/*
>>> + *
>>> + */
>>> +extern int build_dir_tree(char *dirname, unsigned long entries,
>>> +		    unsigned long depth, int is_random)
>>> +{
>>> +	unsigned long i, dir_dirents, file_dirents;
>>> +	char fullpath[PATH_MAX];
>>> +	char dirent[OCFS2_MAX_FILENAME_LEN];
>>> +	unsigned long layer = depth;
>>> +
>>> +	int fd, ret;
>>> +
>>> +	ret = mkdir(dirname, FILE_MODE);
>>> +	if (ret < 0) {
>>> +		ret = errno;
>>> +		fprintf(stderr, "mkdir failure %d: %s\n", ret,
>>> +			strerror(ret));
>>> +		return ret;
>>> +	}
>>> +
>>> +	if (layer == 0)
>>> +		return;
>>> +
>>> +	if (is_random)
>>> +		dir_dirents = get_rand(1, entries - 1);
>>> +	else
>>> +		dir_dirents = entries / 2;
>>> +
>>> +	file_dirents = entries - dir_dirents;
>>> +
>>> +	for (i = 0; i < file_dirents; i++) {
>>> +		if (is_random) {
>>> +			get_rand_nam(dirent, 1, OCFS2_MAX_FILENAME_LEN - 20);
>>> +			snprintf(fullpath, PATH_MAX, "%s/%s%ld%ld",
>>> +				 dirname, dirent, layer, i);
>>> +		} else 
>>> +			snprintf(fullpath, PATH_MAX, "%s/%s%ld%ld",
>>> +				 dirname, "F", layer, i);
>>> +		if (strlen(fullpath) > PATH_MAX)
>>> +			return;
>>> +		fd = open(fullpath, FILE_BUFFERED_RW_FLAGS, FILE_MODE);
>>> +		if (fd < 0) {
>>> +			ret = errno;
>>> +			fprintf(stderr, "create file failure %d: %s,"
>>> +				"filename = %s\n", ret, strerror(ret),
>>> +				fullpath);
>>> +			return ret;
>>> +		}
>>> +
>>> +		close(fd);
>>> +	}
>>> +
>>> +	for (i = 0; i < dir_dirents; i++) {
>>> +		if (is_random) {
>>> +			get_rand_nam(dirent, 1, OCFS2_MAX_FILENAME_LEN - 20);
>>> +			snprintf(fullpath, PATH_MAX, "%s/%s%ld%ld",
>>> +				 dirname, dirent, layer, i);
>>> +		} else
>>> +			snprintf(fullpath, PATH_MAX, "%s/%s%ld%ld",
>>> +				 dirname, "D", layer, i);
>>> +		if (strlen(fullpath) > PATH_MAX)
>>> +			return;
>>> +
>>> +		build_dir_tree(fullpath, entries, layer - 1, is_random);
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +extern int set_semvalue(int sem_id)
>>> +{
>>> +        union semun sem_union;
>>> +
>>> +        sem_union.val = 1;
>>> +        if (semctl(sem_id, 0, SETVAL, sem_union) == -1) {
>>> +                perror("semctl");
>>> +                return -1;
>>> +        }
>>> +
>>> +        return 0;
>>> +}
>>> +
>>> +extern int semaphore_p(int sem_id)
>>> +{
>>> +        struct sembuf sem_b;
>>> +
>>> +        sem_b.sem_num = 0;
>>> +        sem_b.sem_op = -1; /* P() */
>>> +        sem_b.sem_flg = SEM_UNDO;
>>> +        if (semop(sem_id, &sem_b, 1) == -1) {
>>> +                fprintf(stderr, "semaphore_p failed\n");
>>> +                return -1;
>>> +        }
>>> +
>>> +        return 0;
>>> +}
>>> +
>>> +extern int semaphore_v(int sem_id)
>>> +{
>>> +        struct sembuf sem_b;
>>> +
>>> +        sem_b.sem_num = 0;
>>> +        sem_b.sem_op = 1; /* V() */
>>> +        sem_b.sem_flg = SEM_UNDO;
>>> +        if (semop(sem_id, &sem_b, 1) == -1) {
>>> +                fprintf(stderr, "semaphore_v failed\n");
>>> +                return -1;
>>> +        }
>>> +
>>> +        return 0;
>>> +}
>>> +
>>> +extern int get_max_inlined_entries(int max_inline_size)
>>> +{
>>> +        unsigned int almost_full_entries;
>>> +	
>>> +	/*
>>> +		Borrowed from mark's inline-dirs test to measure
>>> +		how to fill up the inlined directory.
>>> +	*/
>>> +	almost_full_entries = max_inline_size / 512;
>>> +	almost_full_entries *= 512;
>>> +	almost_full_entries /= 32;
>>> +
>>> +	almost_full_entries += 8;
>>> +
>>> +
>>> +	return almost_full_entries;
>>> +}
>>> +
>>> diff --git a/programs/libocfs2test/dir_ops.h b/programs/libocfs2test/dir_ops.h
>>> new file mode 100644
>>> index 0000000..a20c181
>>> --- /dev/null
>>> +++ b/programs/libocfs2test/dir_ops.h
>>> @@ -0,0 +1,85 @@
>>> +/* -*- mode: c; c-basic-offset: 8; -*-
>>> + * vim: noexpandtab sw=8 ts=8 sts=0:
>>> + *
>>> + * dir_ops.h
>>> + *
>>> + * Copyright (C) 2008 Oracle.  All rights reserved.
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU General Public
>>> + * License version 2 as published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + * General Public License for more details.
>>> + */
>>> +
>>> +#ifndef DIR_OPS_H
>>> +#define DIR_OPS_H
>>> +
>>> +#define _XOPEN_SOURCE 600
>>> +#define _GNU_SOURCE
>>> +#define _LARGEFILE64_SOURCE
>>> +
>>> +#include <sys/mman.h>
>>> +#include <sys/types.h>
>>> +#include <sys/stat.h>
>>> +#include <sys/vfs.h>
>>> +#include <sys/shm.h>
>>> +#include <sys/sem.h>
>>> +#include <unistd.h>
>>> +#include <fcntl.h>
>>> +#include <limits.h>
>>> +
>>> +#include <ocfs2/ocfs2.h>
>>> +
>>> +#include <dirent.h>
>>> +
>>> +#include <stddef.h>
>>> +#include <stdio.h>
>>> +#include <stdlib.h>
>>> +#include <errno.h>
>>> +#include <string.h>
>>> +
>>> +#include <signal.h>
>>> +#include <sys/wait.h>
>>> +#include <inttypes.h>
>>> +
>>> +#define OCFS2_MAX_FILENAME_LEN          255
>>> +#define MAX_DIRENTS                     40000
>>> +
>>> +#define FILE_BUFFERED_RW_FLAGS  (O_CREAT|O_RDWR|O_TRUNC)
>>> +#define FILE_MODE               (S_IRUSR|S_IWUSR|S_IXUSR|S_IROTH|\
>>> +                                 S_IWOTH|S_IXOTH|S_IRGRP|S_IWGRP|S_IXGRP)
>>> +
>>> +struct my_dirent {
>>> +	unsigned int    type;
>>> +	unsigned int    name_len;
>>> +	unsigned int    seen;
>>> +	char            name[OCFS2_MAX_FILENAME_LEN];
>>> +};
>>> +
>>> +union semun {
>>> +	int val;                    /* value for SETVAL */
>>> +	struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
>>> +	unsigned short int *array;  /* array for GETALL, SETALL */
>>> +	struct seminfo *__buf;      /* buffer for IPC_INFO */
>>> +};
>>> +
>>> +int is_dot_entry(struct my_dirent *dirent);
>>> +int unlink_dirent(char *dirname, struct my_dirent *dirent);
>>> +int create_and_prep_dir(char *dirname);
>>> +int destroy_dir(char *dirname);
>>> +struct my_dirent *find_my_dirent(char *name);
>>> +int create_file(char *filename, char *dirname);
>>> +int create_files(char *prefix, unsigned long num, char *dirname);
>>> +int is_dir_empty(char *name);
>>> +int build_dir_tree(char *dirname, unsigned long entries, unsigned long depth,
>>> +		   int is_random);
>>> +int set_semvalue(int sem_id);
>>> +int semaphore_p(int sem_id);
>>> +int semaphore_v(int sem_id);
>>> +int get_max_inlined_entries(int max_inline_size);
>>> +
>>> +#endif
>>>   
>>>       
>
>   




More information about the Ocfs2-test-devel mailing list