package: debpool severity: wishlist tags: patch Linux::Inotify2 can tell you when a new file is written to the incoming directory without the need for stat()ing or even scanning the directory. This would be a cool feature but should be optional as it requires a recent Linux kernel.
To implement this, I suggest that you move the initial Scan_Changes() call outside the main loop. Then let Monitor_Incoming() such that it will return a list of new .changes files, using Inotify2 if configured to do so, and the old method otherwise. To work optimally (and eliminate the race condition), the watch should be set up once and used throughout the lifetime of the daemon. -- Magnus Holmgren [EMAIL PROTECTED]
--- debpool-0.2.3/share/DebPool/Dirs.pm 2007-03-17 19:34:21.855953186 +0100 +++ debpool-0.2.4/share/DebPool/Dirs.pm 2007-03-17 19:32:45.780180502 +0100 @@ -60,6 +60,7 @@ @EXPORT_OK = qw( &Archfile &Create_Tree + &Setup_Incoming_Watch &Monitor_Incoming &PoolBasePath &PoolDir @@ -69,7 +70,7 @@ ); %EXPORT_TAGS = ( - 'functions' => [qw(&Archfile &Create_Tree &Monitor_Incoming + 'functions' => [qw(&Archfile &Create_Tree &Tree_Mkdir &Setup_Incoming_Watch &Monitor_Incoming &PoolBasePath &PoolDir &Scan_Changes &Scan_All &Strip_Subsection)], 'vars' => [qw()], @@ -87,6 +88,8 @@ our($Error); +my($inotify); + ### File lexicals # None @@ -313,10 +316,62 @@ return [EMAIL PROTECTED]; } +# Setup_Incoming_Watch() +# +# Creates a Linux::Inotify2 object and adds a watch on the incoming directory. +# Returns 1 on success, 0 on failure (and sets $Error). + +sub Setup_Incoming_Watch { + use DebPool::Logging qw(:functions :facility :level); + use DebPool::Config; + require Linux::Inotify2; + + $inotify = new Linux::Inotify2; + if (!$inotify) { + $Error = "Unable to create new inotify object: $!"; + return 0; + } + if (!$inotify->watch($Options{'incoming_dir'}, + Linux::Inotify2->IN_CLOSE_WRITE | + Linux::Inotify2->IN_MOVE_TO )) { + $Error = "Unable to watch $Options{'incoming_dir'}: $!"; + return 0; + } + Log_Message("Watching $Options{'incoming_dir'} with Inotify", + LOG_GENERAL, LOG_DEBUG); + return 1; +} + +# Watch_Incoming() +# +# Reads events from the Inotify2 object (blocking until one occurs), +# picks out the .changes file(s) and returns them (if any; otherwise +# it loops). +# +# Returns a list of .changes files on success, undef on failure (which +# includes interruption by a signal). + +sub Watch_Incoming { + use DebPool::Logging qw(:functions :facility :level); + + do { + my @events = $inotify->read; + return undef if [EMAIL PROTECTED]; + + my @changes = grep(/\.changes$/, map { $_->name; } @events); + if (@changes > 0) { + Log_Message("Found changes: ".join(', ', @changes), + LOG_GENERAL, LOG_DEBUG); + return @changes; + } + } +} + # Monitor_Incoming() # # Monitors the incoming directory, looping until the directory is updated. -# Returns 1 on success, 0 on failure (and sets $Error). +# Returns a list of .changes files on success, undef on failure (which +# includes interruption by a signal - check $DebPool::Signal::Signal_Caught). sub Monitor_Incoming { use DebPool::Config; @@ -327,29 +383,35 @@ # further. if ($DebPool::Signal::Signal_Caught) { - return 1; + return undef; } - my(@stat) = stat($Options{'incoming_dir'}); - if ([EMAIL PROTECTED]) { - $Error = "Couldn't stat incoming_dir '$Options{'incoming_dir'}'"; - return 0; + if ($Options{'use_inotify'}) { + return Watch_Incoming(); } - my($mtime) = $stat[9]; - - do { - Log_Message("Incoming monitor: sleeping for " . - $Options{'sleep'} . " seconds", LOG_GENERAL, LOG_DEBUG); - sleep($Options{'sleep'}); - @stat = stat($Options{'incoming_dir'}); + else { + my(@stat) = stat($Options{'incoming_dir'}); if ([EMAIL PROTECTED]) { $Error = "Couldn't stat incoming_dir '$Options{'incoming_dir'}'"; - return 0; + return undef; } - } until (($stat[9] != $mtime) || ($DebPool::Signal::Signal_Caught)); + my($mtime) = $stat[9]; - return 1; + do { + Log_Message("Incoming monitor: sleeping for " . + $Options{'sleep'} . " seconds", LOG_GENERAL, LOG_DEBUG); + sleep($Options{'sleep'}); + @stat = stat($Options{'incoming_dir'}); + if ([EMAIL PROTECTED]) { + $Error = "Couldn't stat incoming_dir '$Options{'incoming_dir'}'"; + return undef; + } + return undef if $DebPool::Signal::Signal_Caught; + } until ($stat[9] != $mtime); + + return Scan_Changes(); + } } # PoolDir($name, $section, $archive_base) --- debpool-0.2.3/share/DebPool/Config.pm 2007-03-17 19:34:35.458097351 +0100 +++ debpool-0.2.4/share/DebPool/Config.pm 2007-03-17 17:13:43.465436581 +0100 @@ -865,7 +865,10 @@ $Options{'sleep'} = 300; $OptionDefs{'sleep'} = 'sleep=i'; +$Options{'use_inotify'} = 0; +$OptionDefs{'use_inotify'} = 'use_inotify'; + =item B<rollback> = I<boolean> This determines whether older packages in the incoming queue are allowed --- debpool-0.2.3/bin/debpool 2007-03-17 19:39:31.351387477 +0100 +++ debpool-0.2.4/bin/debpool 2007-03-17 19:37:56.260990765 +0100 @@ -138,6 +138,15 @@ close(LOCK_FILE); } +if ($Options{'daemon'} && $Options{'use_inotify'}) { + # Fall back to normal monitoring if Inotify setup fails. + Setup_Incoming_Watch() or $Options{'use_inotify'} = 0; +} + +# Check for any changes files in the incoming directory. + +my(@changefiles) = Scan_Changes($Options{'incoming_dir'}); + # Start the main loop. We use a do/until loop so that we always fire off at # least once. @@ -163,10 +172,6 @@ } } -# Check for any changes files in the incoming directory. - -my(@changefiles) = Scan_Changes($Options{'incoming_dir'}); - # Go through each of the changes files we found, and process it. This is the # heart of things. @@ -640,7 +645,8 @@ if ($Options{'daemon'}) { Log_Message("Waiting on changes to incoming dir.", LOG_GENERAL, LOG_DEBUG); - if (!Monitor_Incoming()) { + @changefiles = Monitor_Incoming(); + if ([EMAIL PROTECTED] && !$Signal_Caught) { my($msg) = "Error in Monitor_Incoming: " . $DebPool::Dirs::Error; Log_Message($msg, LOG_GENERAL, LOG_ERROR); }
pgppGnrplsWio.pgp
Description: PGP signature