Author: stefan2
Date: Sun Dec 18 13:26:08 2011
New Revision: 1220392

URL: http://svn.apache.org/viewvc?rev=1220392&view=rev
Log:
On file_handle_cache branch: 
The flush operation will now only remove handles for the specified file name. 
Also, the file handle cache will be a FSFS session (FFD) - local object because
the membuffer cache eliminates the need to share handles between requests.
This also reduces the need for clever long-term memory management.

* subversion/include/private/svn_file_handle_cache.h
  (svn_file_handle_cache__flush): add file_name parameter
  (svn_file_handle_cache__get_global_cache): drop
* subversion/libsvn_subr/svn_file_handle_cache.c
  (internal_close_file): add support for files still being used by the 
application
  (svn_file_handle_cache__flush_internal): re-implement
  (svn_file_handle_cache__flush): adapt pass-through function
* subversion/libsvn_subr/svn_cache_config.c
  (svn_file_handle_cache__get_global_cache): drop

* subversion/libsvn_fs_fs/fs_fs.c
  (sync_file_handle_cache_and_close): renamed from sync_file_handle_cache;
   now it is "close file and leave no cache entries for it"
  (svn_fs_fs__put_node_revision, write_next_ids, svn_fs_fs__set_entry,
   svn_fs_fs__add_change, rep_write_contents_close, svn_fs_fs__set_proplist,
   commit_body): adapt callers
* subversion/libsvn_fs_fs/caching.c
  (close_unused_file_handles): drop, no longer used
  (init_callbacks): no specific clean-up for file handle cache necessary anymore
  (svn_fs_fs__initialize_caches): create a local file handle cache instance

Modified:
    
subversion/branches/file-handle-cache/subversion/include/private/svn_file_handle_cache.h
    subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/caching.c
    subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs_fs.c
    
subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_cache_config.c
    
subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_file_handle_cache.c

Modified: 
subversion/branches/file-handle-cache/subversion/include/private/svn_file_handle_cache.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/include/private/svn_file_handle_cache.h?rev=1220392&r1=1220391&r2=1220392&view=diff
==============================================================================
--- 
subversion/branches/file-handle-cache/subversion/include/private/svn_file_handle_cache.h
 (original)
+++ 
subversion/branches/file-handle-cache/subversion/include/private/svn_file_handle_cache.h
 Sun Dec 18 13:26:08 2011
@@ -104,10 +104,13 @@ svn_error_t *
 svn_file_handle_cache__close(svn_file_handle_cache__handle_t *f);
 
 /**
- * Close all file handles currently not held by the application.
+ * Close all file handles pertaining to the given FILE_NAME currently not
+ * held by the application and disconnect those held by the application
+ * from CACHE.
  */
 svn_error_t *
-svn_file_handle_cache__flush(svn_file_handle_cache_t *cache);
+svn_file_handle_cache__flush(svn_file_handle_cache_t *cache, 
+                             const char *file_name);
 
 /**
  * Creates a new file handle cache in @a cache. Up to @a max_handles
@@ -123,14 +126,6 @@ svn_file_handle_cache__create_cache(svn_
                                     svn_boolean_t thread_safe,
                                     apr_pool_t *pool);
 
-/**
- * Access the process-global (singleton) open file handle cache. The first
- * call will automatically allocate the cache using the current cache config.
- * Even for file handle limit of 0, a cache object will be returned.
- */
-svn_file_handle_cache_t *
-svn_file_handle_cache__get_global_cache(void);
-
 /** @} */
 
 

Modified: 
subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/caching.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/caching.c?rev=1220392&r1=1220391&r2=1220392&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/caching.c 
(original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/caching.c Sun 
Dec 18 13:26:08 2011
@@ -93,34 +93,6 @@ warn_on_cache_errors(svn_error_t *err,
   return SVN_NO_ERROR;
 }
 
-static apr_status_t
-close_unused_file_handles(void *cache_void)
-{
-  svn_file_handle_cache_t *cache = cache_void;
-  apr_status_t result = APR_SUCCESS;
-
-  /* Close all file handles that are not in use anymore. So, as long as
-   * no requests to a given repository are being processed, we may change
-   * the file content and / or structure. However, content that has been
-   * cached *above* the APR layer (e.g. fulltext caches) will *not* be
-   * changed and may become inconsistent with the disk content.
-   *
-   * This will cause concurrent threads to perform somewhat slower because
-   * they might have put those handles to good use a few moments later.
-   * They now have to actually re-open the respective files.
-   */
-  svn_error_t *err = svn_file_handle_cache__flush(cache);
-
-  /* process error returns */
-  if (err)
-  {
-    result = err->apr_err;
-    svn_error_clear(err);
-  }
-
-  return result;
-}
-
 #ifdef SVN_DEBUG_CACHE_DUMP_STATS
 /* Baton to be used for the dump_cache_statistics() pool cleanup function, */
 struct dump_cache_baton_t
@@ -212,12 +184,6 @@ init_callbacks(svn_cache__t *cache,
                                              warn_on_cache_errors,
                                              fs,
                                              pool));
-
-      /* Schedule file handle cache cleanup after finishing the request. */
-      apr_pool_cleanup_register(pool,
-                                svn_file_handle_cache__get_global_cache(),
-                                close_unused_file_handles,
-                                apr_pool_cleanup_null);
     }
 
   return SVN_NO_ERROR;
@@ -408,7 +374,11 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
   SVN_ERR(init_callbacks(ffd->node_revision_cache, fs, no_handler, pool));
 
   /* initialize file handle cache as configured */
-  ffd->file_handle_cache = svn_file_handle_cache__get_global_cache();
+  SVN_ERR(svn_file_handle_cache__create_cache
+             (&ffd->file_handle_cache,
+              svn_cache_config_get()->file_handle_count,
+              FALSE,
+              fs->pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs_fs.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs_fs.c?rev=1220392&r1=1220391&r2=1220392&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs_fs.c 
(original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs_fs.c Sun 
Dec 18 13:26:08 2011
@@ -611,15 +611,24 @@ with_txn_current_lock(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
-/* A frequently used utility method: close all cached, idle file handles.
- * Call this at the end of write transactions to ensure that successive
- * reads will see the new file content.
+/* A frequently used utility method: the given FILE using POOL. Also
+ * remove all entries for the respective file name from the file handle
+ * cache in FS.
  */
 static svn_error_t *
-sync_file_handle_cache(svn_fs_t *fs)
+sync_file_handle_cache_and_close(svn_fs_t *fs,
+                                 apr_file_t *file,
+                                 apr_pool_t *pool)
 {
+  const char *file_name = "";
   fs_fs_data_t *ffd = fs->fsap_data;
-  return svn_file_handle_cache__flush(ffd->file_handle_cache);
+  
+  apr_status_t apr_err = apr_file_name_get(&file_name, file);
+  if (apr_err)
+    return svn_error_wrap_apr(apr_err, _("Can't get file name"));
+  
+  SVN_ERR(svn_io_file_close(file, pool));
+  return svn_file_handle_cache__flush(ffd->file_handle_cache, file_name);
 }
 
 /* A structure used by unlock_proto_rev() and unlock_proto_rev_body(),
@@ -2541,10 +2550,8 @@ svn_fs_fs__put_node_revision(svn_fs_t *f
                                    svn_fs_fs__fs_supports_mergeinfo(fs),
                                    pool));
 
-  SVN_ERR(svn_io_file_close(noderev_file, pool));
-
   /* we wrote to the db -> sync file contents */
-  return sync_file_handle_cache(fs);
+  return sync_file_handle_cache_and_close(fs, noderev_file, pool);
 }
 
 
@@ -5039,10 +5046,9 @@ write_next_ids(svn_fs_t *fs,
   SVN_ERR(svn_stream_printf(out_stream, pool, "%s %s\n", node_id, copy_id));
 
   SVN_ERR(svn_stream_close(out_stream));
-  SVN_ERR(svn_io_file_close(file, pool));
 
   /* we wrote to the db -> sync file contents */
-  return sync_file_handle_cache(fs);
+  return sync_file_handle_cache_and_close(fs, file, pool);
 }
 
 /* Find out what the next unique node-id and copy-id are for
@@ -5280,10 +5286,8 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
                                 strlen(name), name));
     }
 
-  SVN_ERR(svn_io_file_close(file, pool));
-
   /* we wrote to the db -> sync file contents */
-  return sync_file_handle_cache(fs);
+  return sync_file_handle_cache_and_close(fs, file, pool);
 }
 
 /* Write a single change entry, path PATH, change CHANGE, and copyfrom
@@ -5384,10 +5388,8 @@ svn_fs_fs__add_change(svn_fs_t *fs,
 
   SVN_ERR(write_change_entry(file, path, change, TRUE, pool));
 
-  SVN_ERR(svn_io_file_close(file, pool));
-
   /* we wrote to the db -> sync file contents */
-  return sync_file_handle_cache(fs);
+  return sync_file_handle_cache_and_close(fs, file, pool);
 }
 
 /* This baton is used by the representation writing streams.  It keeps
@@ -5667,12 +5669,12 @@ rep_write_contents_close(void *baton)
   SVN_ERR(svn_fs_fs__put_node_revision(b->fs, b->noderev->id, b->noderev, 
FALSE,
                                        b->pool));
 
-  SVN_ERR(svn_io_file_close(b->file, b->pool));
+  SVN_ERR(sync_file_handle_cache_and_close(b->fs, b->file, b->pool));
   SVN_ERR(unlock_proto_rev(b->fs, rep->txn_id, b->lockcookie, b->pool));
   svn_pool_destroy(b->pool);
 
   /* we wrote to the db -> sync file contents */
-  return sync_file_handle_cache(b->fs);
+  return SVN_NO_ERROR;
 }
 
 /* Store a writable stream in *CONTENTS_P that will receive all data
@@ -5764,7 +5766,7 @@ svn_fs_fs__set_proplist(svn_fs_t *fs,
                            | APR_BUFFERED, APR_OS_DEFAULT, pool));
   out = svn_stream_from_aprfile2(file, TRUE, pool);
   SVN_ERR(svn_hash_write2(proplist, out, SVN_HASH_TERMINATOR, pool));
-  SVN_ERR(svn_io_file_close(file, pool));
+  SVN_ERR(sync_file_handle_cache_and_close(fs, file, pool));
 
   /* Mark the node-rev's prop rep as mutable, if not already done. */
   if (!noderev->prop_rep || !noderev->prop_rep->txn_id)
@@ -5775,7 +5777,7 @@ svn_fs_fs__set_proplist(svn_fs_t *fs,
     }
 
   /* we wrote to the db -> sync file contents */
-  return sync_file_handle_cache(fs);
+  return SVN_NO_ERROR;
 }
 
 /* Read the 'current' file for filesystem FS and store the next
@@ -6394,10 +6396,9 @@ commit_body(void *baton, apr_pool_t *poo
   SVN_ERR(svn_io_file_write_full(proto_file, buf, strlen(buf), NULL,
                                  pool));
   SVN_ERR(svn_io_file_flush_to_disk(proto_file, pool));
-  SVN_ERR(svn_io_file_close(proto_file, pool));
 
   /* we wrote to the db -> sync file contents */
-  SVN_ERR(sync_file_handle_cache(cb->fs));
+  SVN_ERR(sync_file_handle_cache_and_close(cb->fs, proto_file, pool));
 
   /* We don't unlock the prototype revision file immediately to avoid a
      race with another caller writing to the prototype revision file

Modified: 
subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_cache_config.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_cache_config.c?rev=1220392&r1=1220391&r2=1220392&view=diff
==============================================================================
--- 
subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_cache_config.c 
(original)
+++ 
subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_cache_config.c 
Sun Dec 18 13:26:08 2011
@@ -160,76 +160,6 @@ svn_cache__get_global_membuffer_cache(vo
   return cache;
 }
 
-/* Access the process-global (singleton) open file handle cache. The first
- * call will automatically allocate the cache using the current cache config.
- * Even for file handle limit of 0, a cache object will be returned.
- */
-svn_file_handle_cache_t *
-svn_file_handle_cache__get_global_cache(void)
-{
-  static svn_file_handle_cache_t * volatile cache = NULL;
-
-  if (!cache)
-    {
-      svn_error_t *err;
-
-      svn_file_handle_cache_t *old_cache = NULL;
-      svn_file_handle_cache_t *new_cache = NULL;
-
-      /* auto-allocate cache */
-      apr_allocator_t *allocator = NULL;
-      apr_pool_t *pool = NULL;
-
-      if (apr_allocator_create(&allocator))
-        return NULL;
-
-      /* APR files are relatively large objects. Make sure we return
-       * memory back to OS after a spike in allocation.
-       */
-      apr_allocator_max_free_set(allocator, 
-                                 SVN_ALLOCATOR_RECOMMENDED_MAX_FREE);
-
-      /* ordinary root pool for using that allocator
-       */
-      pool = svn_pool_create_ex(NULL, allocator);
-      apr_allocator_owner_set(allocator, pool);
-
-      /* now, create the new cache object
-       */
-      err = svn_file_handle_cache__create_cache(
-          &new_cache,
-          svn_cache_config_get()->file_handle_count,
-          !svn_cache_config_get()->single_threaded,
-          pool);
-
-      /* Some error occured. An new and therefore empty cache is a
-       * a relatively small object, so memory usage is not an issue
-       * right now. Moreover, we rely on the cache being available
-       * (even if the capacity was zero).
-       */
-      if (err)
-        {
-          /* Not much we can do here other than bail out ...
-           */
-          SVN_ERR_MALFUNCTION_NO_RETURN();
-        }
-
-      /* Handle race condition: if we are the first to create a
-       * cache object, make it our global singleton. Otherwise,
-       * discard the new cache and keep the existing one.
-       *
-       * Cast is necessary because of APR bug:
-       * https://issues.apache.org/bugzilla/show_bug.cgi?id=50731
-       */
-      old_cache = apr_atomic_casptr((volatile void **)&cache, new_cache, NULL);
-      if (old_cache != NULL)
-        apr_pool_destroy(pool);
-    }
-
-  return cache;
-}
-
-
 void
 svn_cache_config_set(const svn_cache_config_t *settings)
 {

Modified: 
subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_file_handle_cache.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_file_handle_cache.c?rev=1220392&r1=1220391&r2=1220392&view=diff
==============================================================================
--- 
subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_file_handle_cache.c
 (original)
+++ 
subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_file_handle_cache.c
 Sun Dec 18 13:26:08 2011
@@ -426,9 +426,16 @@ internal_file_open(cache_entry_t **resul
 static svn_error_t *
 internal_close_file(svn_file_handle_cache_t *cache, cache_entry_t *entry)
 {
-  /* any cached file handle held by the application must have either
-   * been returned or invalidated before, i.e. this entry must be "idle" */
-  assert(! entry->open_handle);
+  /* If the application still used this file, disconnect it from the cache.
+   */
+  if (entry->open_handle)
+    {
+      entry->open_handle->cache = NULL;
+      entry->open_handle->entry = NULL;
+      
+      entry->open_handle = NULL;
+      entry->file = NULL;
+    }
 
   /* remove entry from the index (if it is in there) and the
    * list of entries for the same file name
@@ -459,7 +466,9 @@ internal_close_file(svn_file_handle_cach
   remove_from_list(&cache->used_entries, &entry->global_link);
 
   /* actually close the file handle. */
-  SVN_ERR(svn_io_file_close(entry->file, entry->pool));
+  if (entry->file)
+    SVN_ERR(svn_io_file_close(entry->file, entry->pool));
+  
   entry->file = NULL;
   entry->name = NULL;
   svn_pool_clear(entry->pool);
@@ -837,29 +846,29 @@ svn_file_handle_cache__close(svn_file_ha
   return SVN_NO_ERROR;
 }
 
-/* Close all file handles currently not held by the application.
+/* Close all cached file handles pertaining to FILE_NAME.
  */
 static svn_error_t *
-svn_file_handle_cache__flush_internal(svn_file_handle_cache_t *cache)
+svn_file_handle_cache__flush_internal(svn_file_handle_cache_t *cache, 
+                                      const char *file_name)
 {
-  /* close all idle file handles */
-  while (cache->idle_entries.count)
-    SVN_ERR(close_oldest_idle(cache));
-
-  /* if the application does not hold any cached file handles, we can
-   * discard all cache structures and re-allocate them to reduce the 
-   * memory footprint.
-   */
-  if (!cache->used_entries.count)
+  cache_entry_t *next;
+  cache_entry_t *entry = find_first(cache, file_name);
+  
+  if (entry)
     {
-      /* release all cache data structures, in particular the ever-growing
-       * hash and the unused cache entries with all their sub-pools.
-       */
-      svn_pool_clear(cache->pool);
+      while (get_previous_entry(&entry->sibling_link))
+        entry = get_previous_entry(&entry->sibling_link);
 
-      /* re-init global structures */
-      cache->first_by_name = apr_hash_make(cache->pool);
-      init_list(&cache->unused_entries);
+      for (next = get_next_entry (&entry->sibling_link); entry; entry = next)
+        {
+          next = get_next_entry (&entry->sibling_link); 
+
+          /* Handles still held by the application will simply be
+           * disconnected from the cache but the underlying file
+           * will not be closed.*/
+          SVN_ERR(internal_close_file(cache, entry));
+        }
     }
 
   return SVN_NO_ERROR;
@@ -869,7 +878,8 @@ svn_file_handle_cache__flush_internal(sv
  * serialize accesss to the internal data.
  */
 svn_error_t *
-svn_file_handle_cache__flush(svn_file_handle_cache_t *cache)
+svn_file_handle_cache__flush(svn_file_handle_cache_t *cache,
+                             const char *file_name)
 {
   SVN_MUTEX__WITH_LOCK(cache->mutex, 
                        svn_file_handle_cache__flush_internal(cache));


Reply via email to