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;
