Hello community,

here is the log from the commit of package perl-Future for openSUSE:Factory 
checked in at 2019-11-15 00:36:29
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/perl-Future (Old)
 and      /work/SRC/openSUSE:Factory/.perl-Future.new.26869 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "perl-Future"

Fri Nov 15 00:36:29 2019 rev:10 rq:748728 version:0.42

Changes:
--------
--- /work/SRC/openSUSE:Factory/perl-Future/perl-Future.changes  2019-06-14 
20:42:49.846349062 +0200
+++ /work/SRC/openSUSE:Factory/.perl-Future.new.26869/perl-Future.changes       
2019-11-15 00:36:33.287705809 +0100
@@ -1,0 +2,15 @@
+Thu Nov 14 09:27:25 UTC 2019 -  <[email protected]>
+
+- updated to 0.42
+   see /usr/share/doc/packages/perl-Future/Changes
+
+  0.42    2019-11-12
+          [CHANGES]
+           * Added Future::Queue
+  
+          [BUGFIXES]
+           * Remove already-completed futures from the on_cancel chain of 
others
+             to avoid the list growing arbitrarily large in some situations; 
e.g
+             easily provoked by long loops in Future::AsyncAwait
+
+-------------------------------------------------------------------

Old:
----
  Future-0.41.tar.gz

New:
----
  Future-0.42.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ perl-Future.spec ++++++
--- /var/tmp/diff_new_pack.glv3XI/_old  2019-11-15 00:36:33.711705777 +0100
+++ /var/tmp/diff_new_pack.glv3XI/_new  2019-11-15 00:36:33.715705777 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           perl-Future
-Version:        0.41
+Version:        0.42
 Release:        0
 %define cpan_name Future
 Summary:        Represent an operation awaiting completion

++++++ Future-0.41.tar.gz -> Future-0.42.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/Changes new/Future-0.42/Changes
--- old/Future-0.41/Changes     2019-06-13 15:42:46.000000000 +0200
+++ new/Future-0.42/Changes     2019-11-12 12:12:30.000000000 +0100
@@ -1,5 +1,14 @@
 Revision history for Future
 
+0.42    2019-11-12
+        [CHANGES]
+         * Added Future::Queue
+
+        [BUGFIXES]
+         * Remove already-completed futures from the on_cancel chain of others
+           to avoid the list growing arbitrarily large in some situations; e.g
+           easily provoked by long loops in Future::AsyncAwait
+
 0.41    2019-06-13
         [CHANGES]
          * Added Future::Exception->throw
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/MANIFEST new/Future-0.42/MANIFEST
--- old/Future-0.41/MANIFEST    2019-06-13 15:42:46.000000000 +0200
+++ new/Future-0.42/MANIFEST    2019-11-12 12:12:30.000000000 +0100
@@ -4,6 +4,7 @@
 lib/Future/Exception.pm
 lib/Future/Mutex.pm
 lib/Future/Phrasebook.pod
+lib/Future/Queue.pm
 lib/Future/Utils.pm
 lib/Test/Future.pm
 lib/Test/Future/Deferred.pm
@@ -37,6 +38,7 @@
 t/35utils-map-void.t
 t/36utils-map.t
 t/40mutex.t
+t/41queue.t
 t/50test-future.t
 t/51test-future-deferred.t
 t/99pod.t
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/META.json new/Future-0.42/META.json
--- old/Future-0.41/META.json   2019-06-13 15:42:46.000000000 +0200
+++ new/Future-0.42/META.json   2019-11-12 12:12:30.000000000 +0100
@@ -39,27 +39,31 @@
    "provides" : {
       "Future" : {
          "file" : "lib/Future.pm",
-         "version" : "0.41"
+         "version" : "0.42"
       },
       "Future::Exception" : {
          "file" : "lib/Future/Exception.pm",
-         "version" : "0.41"
+         "version" : "0.42"
       },
       "Future::Mutex" : {
          "file" : "lib/Future/Mutex.pm",
-         "version" : "0.41"
+         "version" : "0.42"
+      },
+      "Future::Queue" : {
+         "file" : "lib/Future/Queue.pm",
+         "version" : "0.42"
       },
       "Future::Utils" : {
          "file" : "lib/Future/Utils.pm",
-         "version" : "0.41"
+         "version" : "0.42"
       },
       "Test::Future" : {
          "file" : "lib/Test/Future.pm",
-         "version" : "0.41"
+         "version" : "0.42"
       },
       "Test::Future::Deferred" : {
          "file" : "lib/Test/Future/Deferred.pm",
-         "version" : "0.41"
+         "version" : "0.42"
       }
    },
    "release_status" : "stable",
@@ -69,6 +73,6 @@
       ],
       "x_IRC" : "irc://irc.perl.org/#io-async"
    },
-   "version" : "0.41",
-   "x_serialization_backend" : "JSON::PP version 4.00"
+   "version" : "0.42",
+   "x_serialization_backend" : "JSON::PP version 4.04"
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/META.yml new/Future-0.42/META.yml
--- old/Future-0.41/META.yml    2019-06-13 15:42:46.000000000 +0200
+++ new/Future-0.42/META.yml    2019-11-12 12:12:30.000000000 +0100
@@ -19,22 +19,25 @@
 provides:
   Future:
     file: lib/Future.pm
-    version: '0.41'
+    version: '0.42'
   Future::Exception:
     file: lib/Future/Exception.pm
-    version: '0.41'
+    version: '0.42'
   Future::Mutex:
     file: lib/Future/Mutex.pm
-    version: '0.41'
+    version: '0.42'
+  Future::Queue:
+    file: lib/Future/Queue.pm
+    version: '0.42'
   Future::Utils:
     file: lib/Future/Utils.pm
-    version: '0.41'
+    version: '0.42'
   Test::Future:
     file: lib/Test/Future.pm
-    version: '0.41'
+    version: '0.42'
   Test::Future::Deferred:
     file: lib/Test/Future/Deferred.pm
-    version: '0.41'
+    version: '0.42'
 requires:
   Carp: '1.25'
   Test::Builder::Module: '0'
@@ -43,5 +46,5 @@
 resources:
   IRC: irc://irc.perl.org/#io-async
   license: http://dev.perl.org/licenses/
-version: '0.41'
+version: '0.42'
 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/README new/Future-0.42/README
--- old/Future-0.41/README      2019-06-13 15:42:46.000000000 +0200
+++ new/Future-0.42/README      2019-11-12 12:12:30.000000000 +0100
@@ -335,7 +335,11 @@
        $on_cancel->( $future )
 
     If passed another Future instance, the passed instance will be
-    cancelled when the original future is cancelled.
+    cancelled when the original future is cancelled. In this case, the
+    reference is only strongly held while the target future remains
+    pending. If it becomes ready, then there is no point trying to cancel
+    it, and so it is removed from the originating future's cancellation
+    list.
 
 USER METHODS
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/lib/Future/Exception.pm 
new/Future-0.42/lib/Future/Exception.pm
--- old/Future-0.41/lib/Future/Exception.pm     2019-06-13 15:42:46.000000000 
+0200
+++ new/Future-0.42/lib/Future/Exception.pm     2019-11-12 12:12:30.000000000 
+0100
@@ -8,7 +8,7 @@
 use strict;
 use warnings;
 
-our $VERSION = '0.41';
+our $VERSION = '0.42';
 
 =head1 NAME
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/lib/Future/Mutex.pm 
new/Future-0.42/lib/Future/Mutex.pm
--- old/Future-0.41/lib/Future/Mutex.pm 2019-06-13 15:42:46.000000000 +0200
+++ new/Future-0.42/lib/Future/Mutex.pm 2019-11-12 12:12:30.000000000 +0100
@@ -9,7 +9,7 @@
 use warnings;
 use 5.010;
 
-our $VERSION = '0.41';
+our $VERSION = '0.42';
 
 use Future;
 
@@ -19,17 +19,17 @@
 
 =head1 SYNOPSIS
 
- use Future::Mutex;
+   use Future::Mutex;
 
- my $mutex = Future::Mutex->new;
+   my $mutex = Future::Mutex->new;
 
- sub do_atomically
- {
-    return $mutex->enter( sub {
-       ...
-       return $f;
-    });
- }
+   sub do_atomically
+   {
+      return $mutex->enter( sub {
+         ...
+         return $f;
+      });
+   }
 
 =head1 DESCRIPTION
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/lib/Future/Queue.pm 
new/Future-0.42/lib/Future/Queue.pm
--- old/Future-0.41/lib/Future/Queue.pm 1970-01-01 01:00:00.000000000 +0100
+++ new/Future-0.42/lib/Future/Queue.pm 2019-11-12 12:12:30.000000000 +0100
@@ -0,0 +1,115 @@
+#  You may distribute under the terms of either the GNU General Public License
+#  or the Artistic License (the same terms as Perl itself)
+#
+#  (C) Paul Evans, 2019 -- [email protected]
+
+package Future::Queue;
+
+use strict;
+use warnings;
+
+our $VERSION = '0.42';
+
+=head1 NAME
+
+C<Future::Queue> - a FIFO queue of values that uses L<Future>s
+
+=head1 SYNOPSIS
+
+   use Future::Queue;
+
+   my $queue = Future::Queue->new;
+
+   my $f = repeat {
+      $queue->shift->then(sub {
+         my ( $thing ) = @_;
+         ...
+      });
+   };
+
+   $queue->push( "a thing" );
+
+=head1 DESCRIPTION
+
+Objects in this class provide a simple FIFO queue the stores arbitrary perl
+values. Values may be added into the queue using the L</push> method, and
+retrieved from it using the L</shift> method.
+
+Values may be stored within the queue object for C<shift> to retrieve later,
+or if the queue is empty then the future that C<shift> returns will be
+completed once an item becomes available.
+
+=cut
+
+=head1 CONSTRUCTOR
+
+=cut
+
+=head2 new
+
+   $queue = Future::Queue->new
+
+Returns a new C<Future::Queue> instance.
+
+=cut
+
+sub new
+{
+   my $class = shift;
+   return bless {
+      items => [],
+      waiters => [],
+   }, $class;
+}
+
+=head2 push
+
+   $queue->push( $item )
+
+Adds a new item into the queue. If the queue was previously empty and there is
+at least one C<shift> future waiting, then the next one will be completed by
+this method.
+
+=cut
+
+sub push :method
+{
+   my $self = shift;
+   my ( $item ) = @_;
+
+   push @{ $self->{items} }, $item;
+   ( shift @{ $self->{waiters} } )->done if @{ $self->{waiters} };
+}
+
+=head2 shift
+
+   $item = $queue->shift->get
+
+Returns a C<Future> that will yield the next item from the queue. If there is
+already an item then this will be taken and the returned future will be
+immediate. If not, then the returned future will be pending, and the next
+C<push> method will complete it.
+
+=cut
+
+sub shift :method
+{
+   my $self = shift;
+
+   if( @{ $self->{items} } ) {
+      return Future->done( shift @{ $self->{items} } );
+   }
+
+   push @{ $self->{waiters} }, my $f = Future->new;
+   return $f->then(sub {
+      return Future->done( shift @{ $self->{items} } );
+   });
+}
+
+=head1 AUTHOR
+
+Paul Evans <[email protected]>
+
+=cut
+
+0x55AA;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/lib/Future/Utils.pm 
new/Future-0.42/lib/Future/Utils.pm
--- old/Future-0.41/lib/Future/Utils.pm 2019-06-13 15:42:46.000000000 +0200
+++ new/Future-0.42/lib/Future/Utils.pm 2019-11-12 12:12:30.000000000 +0100
@@ -8,7 +8,7 @@
 use strict;
 use warnings;
 
-our $VERSION = '0.41';
+our $VERSION = '0.42';
 
 use Exporter 'import';
 # Can't import the one from Exporter as it relies on package inheritance
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/lib/Future.pm 
new/Future-0.42/lib/Future.pm
--- old/Future-0.41/lib/Future.pm       2019-06-13 15:42:46.000000000 +0200
+++ new/Future-0.42/lib/Future.pm       2019-11-12 12:12:30.000000000 +0100
@@ -9,7 +9,7 @@
 use warnings;
 no warnings 'recursion'; # Disable the "deep recursion" warning
 
-our $VERSION = '0.41';
+our $VERSION = '0.42';
 
 use Carp qw(); # don't import croak
 use Scalar::Util qw( weaken blessed reftype );
@@ -377,6 +377,9 @@
    }
 
    delete $self->{on_cancel};
+   $_->[0] and $_->[0]->_revoke_on_cancel( $_->[1] ) for @{ 
$self->{revoke_when_ready} };
+   delete $self->{revoke_when_ready};
+
    my $callbacks = delete $self->{callbacks} or return;
 
    my $cancelled = $self->{cancelled};
@@ -700,7 +703,10 @@
    $on_cancel->( $future )
 
 If passed another C<Future> instance, the passed instance will be cancelled
-when the original future is cancelled.
+when the original future is cancelled. In this case, the reference is only
+strongly held while the target future remains pending. If it becomes ready,
+then there is no point trying to cancel it, and so it is removed from the
+originating future's cancellation list.
 
 =cut
 
@@ -716,10 +722,37 @@
    $self->{ready} and return $self;
 
    push @{ $self->{on_cancel} }, $code;
+   if( $is_future ) {
+      push @{ $code->{revoke_when_ready} }, my $r = [ $self, 
\$self->{on_cancel}[-1] ];
+      weaken( $r->[0] );
+      weaken( $r->[1] );
+   }
 
    return $self;
 }
 
+sub _revoke_on_cancel
+{
+   my $self = shift;
+   my ( $ref ) = @_;
+
+   undef $$ref;
+   $self->{empty_on_cancel_slots}++;
+
+   my $on_cancel = $self->{on_cancel} or return;
+
+   # If the list is nontrivally large and over half-empty / under half-full, 
compact it
+   if( @$on_cancel >= 8 and $self->{empty_on_cancel_slots} >= 0.5 * 
@$on_cancel ) {
+      # We can't grep { defined } because that will break all the existing 
SCALAR refs
+      my $idx = 0;
+      while( $idx < @$on_cancel ) {
+         defined $on_cancel->[$idx] and $idx++, next;
+         splice @$on_cancel, $idx, 1, ();
+      }
+      $self->{empty_on_cancel_slots} = 0;
+   }
+}
+
 =head1 USER METHODS
 
 These methods would primarily be used by users of asynchronous interfaces, on
@@ -1036,7 +1069,9 @@
    return $self if $self->{ready};
 
    $self->{cancelled}++;
-   foreach my $code ( reverse @{ $self->{on_cancel} || [] } ) {
+   my $on_cancel = delete $self->{on_cancel};
+   foreach my $code ( $on_cancel ? reverse @$on_cancel : () ) {
+      defined $code or next;
       my $is_future = blessed( $code ) && $code->isa( "Future" );
       $is_future ? $code->cancel
                  : $code->( $self );
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/lib/Test/Future/Deferred.pm 
new/Future-0.42/lib/Test/Future/Deferred.pm
--- old/Future-0.41/lib/Test/Future/Deferred.pm 2019-06-13 15:42:46.000000000 
+0200
+++ new/Future-0.42/lib/Test/Future/Deferred.pm 2019-11-12 12:12:30.000000000 
+0100
@@ -9,7 +9,7 @@
 use warnings;
 use base qw( Future );
 
-our $VERSION = '0.41';
+our $VERSION = '0.42';
 
 =head1 NAME
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/lib/Test/Future.pm 
new/Future-0.42/lib/Test/Future.pm
--- old/Future-0.41/lib/Test/Future.pm  2019-06-13 15:42:46.000000000 +0200
+++ new/Future-0.42/lib/Test/Future.pm  2019-11-12 12:12:30.000000000 +0100
@@ -9,7 +9,7 @@
 use warnings;
 use base qw( Test::Builder::Module );
 
-our $VERSION = '0.41';
+our $VERSION = '0.42';
 
 our @EXPORT = qw(
    no_pending_futures
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/t/02cancel.t new/Future-0.42/t/02cancel.t
--- old/Future-0.41/t/02cancel.t        2019-06-13 15:42:46.000000000 +0200
+++ new/Future-0.42/t/02cancel.t        2019-11-12 12:12:30.000000000 +0100
@@ -84,8 +84,18 @@
 {
    my $f1 = Future->new;
    my $f2 = Future->new;
+   my $f3 = Future->new;
 
    $f1->on_cancel( $f2 );
+   $f1->on_cancel( $f3 );
+
+   is_oneref( $f1, '$f1 has refcount 1 after on_cancel chaining' );
+   is_refcount( $f2, 2, '$f2 has refcount 2 after on_cancel chaining' );
+   is_refcount( $f3, 2, '$f3 has refcount 2 after on_cancel chaining' );
+
+   $f3->done;
+   is_oneref( $f3, '$f3 has refcount 1 after done in cancel chain' );
+
    my $cancelled;
    $f2->on_cancel( sub { $cancelled++ } );
 
@@ -93,6 +103,37 @@
    is( $cancelled, 1, 'Chained cancellation' );
 }
 
+# test amortized compaction
+{
+   my $f = Future->new;
+   my @subf;
+
+   push @subf, Future->new and $f->on_cancel( $subf[-1] ) for 1 .. 100;
+
+   # gutwrench
+   is( scalar @{ $f->{on_cancel} }, 100, '$f on_cancel list is 100 items 
initially' );
+
+   # We should be able to cancel the first 49 of these without triggering a 
compaction
+   $_->done for @subf[0..48];
+
+   # gutwrench
+   is( scalar @{ $f->{on_cancel} }, 100, '$f on_cancel list still 100 items' );
+
+   # Cancelling the next one will cause a compaction
+   $_->done for $subf[49];
+
+   # gutwrench
+   is( scalar @{ $f->{on_cancel} }, 50, '$f on_cancel list now only 50 items' 
);
+
+   # Cancelling most of the rest will compact again
+   $_->done for @subf[50..90];
+
+   # gutwrench
+   is( scalar @{ $f->{on_cancel} }, 12, '$f on_cancel list now only 12 items' 
);
+
+   $f->cancel;
+}
+
 # ->done on cancelled
 {
    my $f = Future->new;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.41/t/41queue.t new/Future-0.42/t/41queue.t
--- old/Future-0.41/t/41queue.t 1970-01-01 01:00:00.000000000 +0100
+++ new/Future-0.42/t/41queue.t 2019-11-12 12:12:30.000000000 +0100
@@ -0,0 +1,35 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More;
+
+use Future;
+use Future::Queue;
+
+# push before shift
+{
+   my $queue = Future::Queue->new;
+
+   $queue->push( "ITEM" );
+
+   my $f = $queue->shift;
+   ok( $f->is_done, '$queue->shift already ready' );
+   is( $f->get, "ITEM", '$queue->shift->get' );
+}
+
+# shift before push
+{
+   my $queue = Future::Queue->new;
+
+   my $f = $queue->shift;
+   ok( !$f->is_done, '$queue->shift not yet ready' );
+
+   $queue->push( "ITEM" );
+
+   ok( $f->is_done, '$queue->shift now ready after push' );
+   is( $f->get, "ITEM", '$queue->shift->get' );
+}
+
+done_testing;


Reply via email to