r4165: added a 100 element name cache to cope with some amount of seeking
authorAndrew Tridgell <tridge@samba.org>
Sun, 12 Dec 2004 11:30:30 +0000 (11:30 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:07:21 +0000 (13:07 -0500)
back to filenames that have been deleted. This fixes the new os/2
delete test.

source/ntvfs/posix/pvfs_dirlist.c
source/ntvfs/posix/pvfs_search.c

index 1ef6e408c30e878ea54860bbee383936473e8844..5c67b2d189d1ac4535f86558475f6ddd1ee1ae7d 100644 (file)
 #include "vfs_posix.h"
 #include "system/dir.h"
 
+#define NAME_CACHE_SIZE 100
+
+struct name_cache_entry {
+       char *name;
+       off_t offset;
+};
+
 struct pvfs_dir {
        struct pvfs_state *pvfs;
        BOOL no_wildcard;
-       char *last_name;
+       char *single_name;
        const char *pattern;
        off_t offset;
        DIR *dir;
        const char *unix_path;
        BOOL end_of_search;
+       struct name_cache_entry *name_cache;
+       uint32_t name_cache_index;
 };
 
 /*
@@ -55,8 +64,8 @@ static NTSTATUS pvfs_list_no_wildcard(struct pvfs_state *pvfs, struct pvfs_filen
                return NT_STATUS_NO_MEMORY;
        }
 
-       dir->last_name = talloc_strdup(dir, pattern);
-       if (!dir->last_name) {
+       dir->single_name = talloc_strdup(dir, pattern);
+       if (!dir->single_name) {
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -88,7 +97,7 @@ NTSTATUS pvfs_list_start(struct pvfs_state *pvfs, struct pvfs_filename *name,
        char *pattern;
        struct pvfs_dir *dir;
 
-       (*dirp) = talloc_p(mem_ctx, struct pvfs_dir);
+       (*dirp) = talloc_zero_p(mem_ctx, struct pvfs_dir);
        if (*dirp == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -126,9 +135,15 @@ NTSTATUS pvfs_list_start(struct pvfs_state *pvfs, struct pvfs_filename *name,
 
        dir->pvfs = pvfs;
        dir->no_wildcard = False;
-       dir->last_name = NULL;
        dir->end_of_search = False;
        dir->offset = 0;
+       dir->name_cache = talloc_zero_array_p(dir, 
+                                             struct name_cache_entry, 
+                                             NAME_CACHE_SIZE);
+       if (dir->name_cache == NULL) {
+               talloc_free(dir);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        talloc_set_destructor(dir, pvfs_dirlist_destructor);
 
@@ -147,7 +162,7 @@ const char *pvfs_list_next(struct pvfs_dir *dir, uint_t *ofs)
                dir->end_of_search = True;
                if (*ofs != 0) return NULL;
                (*ofs)++;
-               return dir->last_name;
+               return dir->single_name;
        }
 
        if (*ofs != dir->offset) {
@@ -157,6 +172,7 @@ const char *pvfs_list_next(struct pvfs_dir *dir, uint_t *ofs)
        
        while ((de = readdir(dir->dir))) {
                const char *dname = de->d_name;
+               struct name_cache_entry *e;
 
                if (ms_fnmatch(dir->pattern, dname, 
                               dir->pvfs->tcon->smb_conn->negotiate.protocol) != 0) {
@@ -173,10 +189,15 @@ const char *pvfs_list_next(struct pvfs_dir *dir, uint_t *ofs)
                dir->offset = telldir(dir->dir);
                (*ofs) = dir->offset;
 
-               if (dir->last_name) talloc_free(dir->last_name);
-               dir->last_name = talloc_strdup(dir, de->d_name);
+               dir->name_cache_index = (dir->name_cache_index+1) % NAME_CACHE_SIZE;
+               e = &dir->name_cache[dir->name_cache_index];
+
+               if (e->name) talloc_free(e->name);
+
+               e->name = talloc_strdup(dir, de->d_name);
+               e->offset = dir->offset;
 
-               return dir->last_name;
+               return e->name;
        }
 
        dir->end_of_search = True;
@@ -248,16 +269,26 @@ NTSTATUS pvfs_list_seek(struct pvfs_dir *dir, const char *name, uint_t *ofs)
 {
        struct dirent *de;
        NTSTATUS status;
+       int i;
 
        status = pvfs_list_wakeup(dir, ofs);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       if (dir->last_name &&
-           StrCaseCmp(name, dir->last_name) == 0) {
-               *ofs = dir->offset;
-               return NT_STATUS_OK;
+       for (i=dir->name_cache_index;i>=0;i--) {
+               struct name_cache_entry *e = &dir->name_cache[i];
+               if (e->name && StrCaseCmp(name, e->name) == 0) {
+                       *ofs = e->offset;
+                       return NT_STATUS_OK;
+               }
+       }
+       for (i=NAME_CACHE_SIZE-1;i>dir->name_cache_index;i--) {
+               struct name_cache_entry *e = &dir->name_cache[i];
+               if (e->name && StrCaseCmp(name, e->name) == 0) {
+                       *ofs = e->offset;
+                       return NT_STATUS_OK;
+               }
        }
 
        rewinddir(dir->dir);
@@ -266,8 +297,6 @@ NTSTATUS pvfs_list_seek(struct pvfs_dir *dir, const char *name, uint_t *ofs)
                if (StrCaseCmp(name, de->d_name) == 0) {
                        dir->offset = telldir(dir->dir);
                        *ofs = dir->offset;
-                       if (dir->last_name) talloc_free(dir->last_name);
-                       dir->last_name = talloc_strdup(dir, de->d_name);
                        return NT_STATUS_OK;
                }
        }
@@ -276,7 +305,5 @@ NTSTATUS pvfs_list_seek(struct pvfs_dir *dir, const char *name, uint_t *ofs)
 
        pvfs_list_hibernate(dir);
 
-       /* it is not an error to give a bad name (it may have been deleted). Instead
-          just continue from end of directory */
-       return NT_STATUS_OK;
+       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 }
index 1c49701f040a37fed649b67b99bf5e5f5c6d4dbb..c3360352180797457e6093394c4d57b27be7c5e9 100644 (file)
@@ -533,7 +533,11 @@ NTSTATUS pvfs_search_next(struct ntvfs_module_context *ntvfs,
        if (io->t2fnext.in.last_name && *io->t2fnext.in.last_name) {
                status = pvfs_list_seek(dir, io->t2fnext.in.last_name, &search->current_index);
                if (!NT_STATUS_IS_OK(status)) {
-                       return status;
+                       if (io->t2fnext.in.resume_key) {
+                               search->current_index = io->t2fnext.in.resume_key;
+                       } else {
+                               return status;
+                       }
                }
        } else if (io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE) {
                /* plain continue - nothing to do */
@@ -562,10 +566,6 @@ NTSTATUS pvfs_search_next(struct ntvfs_module_context *ntvfs,
                talloc_free(search);
        }
 
-       if (reply_count == 0) {
-               return NT_STATUS_NO_SUCH_FILE;
-       }
-
        return NT_STATUS_OK;
 }