On 22 May 2015 at 09:40, Branko Čibej <br...@wandisco.com> wrote:
> On 22.05.2015 00:09, Philip Martin wrote:
>> Ivan Zhakov <i...@visualsvn.com> writes:
>>
>>> We considered adding FLUSH_TO_DISK flag to svn_stream_from_apr_file(),
>>> but decided to commit simple fix for now:
>>> 1. The current FSFS code uses explicit flush and this commit makes
>>> code consistent with other parts
>>> 2. Adding flag to svn_stream_from_apr_file() will require revving API
>>> etc, while this fix should be backported to 1.8.x and 1.9.x
>
> The API argument only applies to 1.8.x, which would need a completely
> different fix; not to 1.9.x, because it's not released yet.
Yes, we can introduce new API in 1.9.x but this automatically this fix
1.9.0 release blocker, while I wanted to avoid blocking 1.9.0 due this
fix since it's not regressing.

> The benefit
> of revising the API (which I tentatively support, see [1] below)
> outweighs the pain of having to write a different fix for 1.8.x.
>

>>> 3. It's unclear how FLUSH_TO_DISK flag should interact with DISOWN=TRUE.
>>>
>>> Taking in account all above we decided to commit simple fix for now
>>> and possibly implement FLUSH_TO_DISK flag later applying it to all
>>> FSFS code where needed.
>> Is it simple?  It's possible that r1680819 is more complicated than
>> adding flush to the the stream.
>>
>> Exactly what the API should look like is bit unclear.  Is there any need
>> to support disown=TRUE and flush=TRUE?  When would Subversion use it?
>> If we create svn_stream_from_aprfile3 that takes two booleans then
>> perhaps we change the return type to allow an error for the impossible
>> disown=TRUE and flush=TRUE.
>
> Yup. There's no reason to try to support mutually conflicting arguments.
But how svn_stream_from_aprfile3() should handle disown=TRUE and
flush=TRUE: assertion, disown=TRUE as priority and ignore flush=TRUE?
I don't say we cannot find good solution for this, I just wanted to
make simple fix targeted for 1.8.x and 1.9.x and then improve all FSFS
regarding flushes.

>
>> All the flushing code goes in libsvn_subr
>
> Just one nit here: the flushing code would indeed be localized in
> libsvn_subr, however, the API change would propagate to some 100 places
> in the code [1], including lots of places in libsvn_fs_fs. That's unless
> we decide /not/ to deprecate svn_stream_from_aprfile2 in the 1.9.x
> series and use it in parallel with the prospective svn_stream_from_aprfile3.
>
Yep, revving svn_stream_from_aprfile2() would introduce changing all
callers. But I agree that we can keep svn_stream_from_aprfile2()
without deprecating.


> FWIW, I think in this case revving the API without deprecating the old
> one is justified. Another option would be to invent a different API name
> for the flushing stream, e.g., svn_stream_from_aprfile_flushed or some
> such. This way we'd also avoid the dilemma about disown by simply not
> having that flag in the new function.
>
There are two kinds of flushes:
1) flush all data buffered in stream implementation
2) ensure that data written to disk hardware

Extending stream API with svn_stream_flush() with (1) semantic seems
to be natural extension, but introducing (2) would be leak of
abstraction.

>> and the code change in FSFS is really small, something like:
>>
>> Index: subversion/libsvn_fs_fs/revprops.c
>> ===================================================================
>> --- subversion/libsvn_fs_fs/revprops.c        (revision 1680818)
>> +++ subversion/libsvn_fs_fs/revprops.c        (working copy)
>> @@ -874,7 +874,7 @@
>>                                                    new_filename->data,
>>                                                    pool),
>>                             APR_WRITE | APR_CREATE, APR_OS_DEFAULT, pool));
>> -  *stream = svn_stream_from_aprfile2(file, FALSE, pool);
>> +  SVN_ERR(svn_stream_from_aprfile3(stream, file, FALSE, TRUE, pool));
>>
>>    return SVN_NO_ERROR;
>>  }
>> @@ -1205,7 +1205,8 @@
>>    SVN_ERR(svn__compress(uncompressed, compressed, compression_level));
>>
>>    /* write the pack file content to disk */
>> -  stream = svn_stream_from_aprfile2(pack_file, FALSE, scratch_pool);
>> +  SVN_ERR(svn_stream_from_aprfile3(&stream, pack_file, FALSE, TRUE,
>> +                                   scratch_pool));
>>    SVN_ERR(svn_stream_write(stream, compressed->data, &compressed->len));
>>    SVN_ERR(svn_stream_close(stream));
>>
>> A patch like that is possibly easier to review than r1680819.
>
> Quite a bit easier, yes.
>
Yes, this patch looks easier to review, the only problem that it's
incomplete. I'm attaching minimal working patch with
svn_stream_from_file3() against trunk@r1680818.


-- 
Ivan Zhakov
Index: subversion/include/svn_io.h
===================================================================
--- subversion/include/svn_io.h (revision 1679771)
+++ subversion/include/svn_io.h (working copy)
@@ -1087,6 +1087,12 @@
                          svn_boolean_t disown,
                          apr_pool_t *pool);
 
+svn_stream_t *
+svn_stream_from_aprfile3(apr_file_t *file,
+                         svn_boolean_t disown,
+                         svn_boolean_t flush_on_close,
+                         apr_pool_t *pool);
+
 /** Similar to svn_stream_from_aprfile2(), except that the file will
  * always be disowned.
  *
Index: subversion/libsvn_fs_fs/revprops.c
===================================================================
--- subversion/libsvn_fs_fs/revprops.c  (revision 1679771)
+++ subversion/libsvn_fs_fs/revprops.c  (working copy)
@@ -657,14 +657,16 @@
                          apr_hash_t *proplist,
                          apr_pool_t *pool)
 {
+  apr_file_t *file;
   svn_stream_t *stream;
   *final_path = svn_fs_fs__path_revprops(fs, rev, pool);
 
   /* ### do we have a directory sitting around already? we really shouldn't
      ### have to get the dirname here. */
-  SVN_ERR(svn_stream_open_unique(&stream, tmp_path,
-                                 svn_dirent_dirname(*final_path, pool),
-                                 svn_io_file_del_none, pool, pool));
+  SVN_ERR(svn_io_open_unique_file3(&file, tmp_path,
+                                   svn_dirent_dirname(*final_path, pool),
+                                   svn_io_file_del_none, pool, pool));
+  stream = svn_stream_from_aprfile3(file, FALSE, TRUE, pool);
   SVN_ERR(svn_hash_write2(proplist, stream, SVN_HASH_TERMINATOR, pool));
   SVN_ERR(svn_stream_close(stream));
 
@@ -879,7 +881,7 @@
                                                   new_filename->data,
                                                   pool),
                            APR_WRITE | APR_CREATE, APR_OS_DEFAULT, pool));
-  *stream = svn_stream_from_aprfile2(file, FALSE, pool);
+  *stream = svn_stream_from_aprfile3(file, FALSE, TRUE, pool);
 
   return SVN_NO_ERROR;
 }
@@ -903,6 +905,7 @@
   packed_revprops_t *revprops;
   apr_int64_t generation = 0;
   svn_stream_t *stream;
+  apr_file_t *file;
   svn_stringbuf_t *serialized;
   apr_off_t new_total_size;
   int changed_index;
@@ -933,8 +936,10 @@
 
       *final_path = svn_dirent_join(revprops->folder, revprops->filename,
                                     pool);
-      SVN_ERR(svn_stream_open_unique(&stream, tmp_path, revprops->folder,
-                                     svn_io_file_del_none, pool, pool));
+      SVN_ERR(svn_io_open_unique_file3(&file, tmp_path, revprops->folder,
+                                       svn_io_file_del_none, pool, pool));
+      stream = svn_stream_from_aprfile3(file, FALSE, TRUE, pool);
+
       SVN_ERR(repack_revprops(fs, revprops, 0, revprops->sizes->nelts,
                               changed_index, serialized, new_total_size,
                               stream, pool));
@@ -1016,8 +1021,9 @@
 
       /* write the new manifest */
       *final_path = svn_dirent_join(revprops->folder, PATH_MANIFEST, pool);
-      SVN_ERR(svn_stream_open_unique(&stream, tmp_path, revprops->folder,
-                                     svn_io_file_del_none, pool, pool));
+      SVN_ERR(svn_io_open_unique_file3(&file, tmp_path, revprops->folder,
+                                       svn_io_file_del_none, pool, pool));
+      stream = svn_stream_from_aprfile3(file, FALSE, TRUE, pool);
 
       for (i = 0; i < revprops->manifest->nelts; ++i)
         {
Index: subversion/libsvn_subr/stream.c
===================================================================
--- subversion/libsvn_subr/stream.c     (revision 1679771)
+++ subversion/libsvn_subr/stream.c     (working copy)
@@ -808,6 +808,7 @@
 struct baton_apr {
   apr_file_t *file;
   apr_pool_t *pool;
+  svn_boolean_t flush_on_close;
 };
 
 /* svn_stream_mark_t for streams backed by APR files. */
@@ -1031,10 +1032,10 @@
   return SVN_NO_ERROR;
 }
 
-
 svn_stream_t *
-svn_stream_from_aprfile2(apr_file_t *file,
+svn_stream_from_aprfile3(apr_file_t *file,
                          svn_boolean_t disown,
+                         svn_boolean_t flush_on_close,
                          apr_pool_t *pool)
 {
   struct baton_apr *baton;
@@ -1046,6 +1047,7 @@
   baton = apr_palloc(pool, sizeof(*baton));
   baton->file = file;
   baton->pool = pool;
+  baton->flush_on_close = flush_on_close;
   stream = svn_stream_create(baton, pool);
   svn_stream_set_read2(stream, read_handler_apr, read_full_handler_apr);
   svn_stream_set_write(stream, write_handler_apr);
@@ -1056,12 +1058,22 @@
   svn_stream__set_is_buffered(stream, is_buffered_handler_apr);
   stream->file = file;
 
-  if (! disown)
-    svn_stream_set_close(stream, close_handler_apr);
+  /* ## TODO: How to handle DISOWN = TRUE and FLUSH_ON_CLOSE=TRUE? */
+  if (!disown)
+      svn_stream_set_close(stream, close_handler_apr);
 
   return stream;
 }
 
+
+svn_stream_t *
+svn_stream_from_aprfile2(apr_file_t *file,
+                         svn_boolean_t disown,
+                         apr_pool_t *pool)
+{
+  return svn_stream_from_aprfile3(file, disown, FALSE, pool);
+}
+
 apr_file_t *
 svn_stream__aprfile(svn_stream_t *stream)
 {

Reply via email to