Browse Source

Add retention time as server parameter (in days, where 0 is infinite).

Jobs older than the retention time of a server will not be tried for that server.
The 'top_only' option is permanently disbled to prevent queue lockup by a job outside the retention time of all servers.
Some fixes and asserts to help static analysers.
tags/0.6.0
ShyPike 15 years ago
parent
commit
f7be067a69
  1. 2
      interfaces/Classic/templates/config_server.tmpl
  2. 9
      interfaces/Plush/templates/config_server.tmpl
  3. 5
      interfaces/smpl/templates/config_server.tmpl
  4. 4
      sabnzbd/config.py
  5. 20
      sabnzbd/downloader.py
  6. 10
      sabnzbd/nzbqueue.py
  7. 6
      sabnzbd/nzbstuff.py
  8. 3
      sabnzbd/skintext.py

2
interfaces/Classic/templates/config_server.tmpl

@ -17,6 +17,7 @@
$T('srv-password'):<br><input type="password" size="25" name="password"><br> $T('srv-password'):<br><input type="password" size="25" name="password"><br>
$T('srv-timeout'):<br><input type="text" size="25" name="timeout" value="120"><br> $T('srv-timeout'):<br><input type="text" size="25" name="timeout" value="120"><br>
$T('srv-connections'):<br><input type="text" size="25" name="connections"><br> $T('srv-connections'):<br><input type="text" size="25" name="connections"><br>
$T('srv-retention') ($T('days')):<br><input type="text" size="25" name="retention"><br>
<!--#if int($have_ssl) == 0#--> <!--#if int($have_ssl) == 0#-->
$T('srv-ssl') $T('opt-notInstalled') $T('srv-ssl') $T('opt-notInstalled')
<!--#else#--> <!--#else#-->
@ -41,6 +42,7 @@
$T('srv-password'):<br><input type="password" size="25" name="password" value="$servers[$server]['password']"><br> $T('srv-password'):<br><input type="password" size="25" name="password" value="$servers[$server]['password']"><br>
$T('srv-timeout'):<br><input type="text" size="25" name="timeout" value="$servers[$server]['timeout']"><br> $T('srv-timeout'):<br><input type="text" size="25" name="timeout" value="$servers[$server]['timeout']"><br>
$T('srv-connections'):<br><input type="text" size="25" name="connections" value="$servers[$server]['connections']"><br> $T('srv-connections'):<br><input type="text" size="25" name="connections" value="$servers[$server]['connections']"><br>
$T('srv-retention'):<br><input type="text" size="25" name="retention" value="$servers[$server]['retention']"><br>
<!--#if int($have_ssl) == 0#--> <!--#if int($have_ssl) == 0#-->
$T('srv-ssl') $T('opt-notInstalled') $T('srv-ssl') $T('opt-notInstalled')
<!--#else#--> <!--#else#-->

9
interfaces/Plush/templates/config_server.tmpl

@ -23,7 +23,8 @@
<table> <table>
<tr><td class="alignRight"><div class="sucker">#&nbsp;$T('srv-connections'):</div></td><td><input type="text" size="5" name="connections"/></td></tr> <tr><td class="alignRight"><div class="sucker">#&nbsp;$T('srv-connections'):</div></td><td><input type="text" size="5" name="connections"/></td></tr>
<tr><td class="alignRight"><div class="sucker">$T('srv-timeout'):</div></td><td><input type="text" size="5" name="timeout" value="120">&nbsp;<small>$T('second')</small></td></tr> <tr><td class="alignRight"><div class="sucker">$T('srv-retention'):</div></td><td><input type="text" size="5" name="retention"/>&nbsp;<small>$T('days')</small></td></tr>
<tr><td class="alignRight"><div class="sucker">$T('srv-timeout'):</div></td><td><input type="text" size="5" name="timeout" value="120">&nbsp;<small>$T('seconds')</small></td></tr>
<tr><td colspan="2">&nbsp;</td></tr> <tr><td colspan="2">&nbsp;</td></tr>
@ -84,8 +85,12 @@
<td><input type="text" size="5" name="connections" value="$servers[$server]['connections']"/></td> <td><input type="text" size="5" name="connections" value="$servers[$server]['connections']"/></td>
</tr> </tr>
<tr> <tr>
<td class="alignRight"><div class="sucker">$T('srv-retention'):</div></td>
<td><input type="text" size="5" name="retention" value="$servers[$server]['retention']"/>&nbsp;<small>$T('days')</small></td>
</tr>
<tr>
<td class="alignRight"><div class="sucker">$T('srv-timeout'):</div></td> <td class="alignRight"><div class="sucker">$T('srv-timeout'):</div></td>
<td><input type="text" size="5" name="timeout" value="$servers[$server]['timeout']"/>&nbsp;<small>seconds</small></td> <td><input type="text" size="5" name="timeout" value="$servers[$server]['timeout']"/>&nbsp;<small>$T('seconds')</small></td>
</tr> </tr>
<tr><td colspan="2">&nbsp;</td></tr> <tr><td colspan="2">&nbsp;</td></tr>
<tr> <tr>

5
interfaces/smpl/templates/config_server.tmpl

@ -22,6 +22,8 @@
<br class="clear" /> <br class="clear" />
<label class="label">$T('srv-connections'):</label><input type="text" size="25" name="connections" value="$servers[$server]['connections']"> <label class="label">$T('srv-connections'):</label><input type="text" size="25" name="connections" value="$servers[$server]['connections']">
<br class="clear" /> <br class="clear" />
<label class="label">$T('srv-retention') ($T('days')):</label><input type="text" size="25" name="retention" value="$servers[$server]['retention']">
<br class="clear" />
<label><span class="label">$T('srv-ssl')<!--#if int($have_ssl) == 0 then $T('opt-notInstalled') else ""#-->:</span> <label><span class="label">$T('srv-ssl')<!--#if int($have_ssl) == 0 then $T('opt-notInstalled') else ""#-->:</span>
<input class="radio" type="checkbox" name="ssl" value="1" <!--#if int($servers[$server]['ssl']) != 0 and int($have_ssl) == 1 then "checked=1" else ""#--> <!--#if int($have_ssl) == 0 then "disabled" else ""#-->/> <input class="radio" type="checkbox" name="ssl" value="1" <!--#if int($servers[$server]['ssl']) != 0 and int($have_ssl) == 1 then "checked=1" else ""#--> <!--#if int($have_ssl) == 0 then "disabled" else ""#-->/>
@ -85,6 +87,9 @@
<label class="label">$T('srv-connections'):</label><input type="text" size="25" name="connections"> <label class="label">$T('srv-connections'):</label><input type="text" size="25" name="connections">
<br class="clear" /> <br class="clear" />
<label class="label">$T('srv-retention') ($T('days')):</label><input type="text" size="25" name="retention">
<br class="clear" />
<label><span class="label">$T('srv-ssl')<!--#if int($have_ssl) == 0 then $T('opt-notInstalled') else ""#-->:</span> <label><span class="label">$T('srv-ssl')<!--#if int($have_ssl) == 0 then $T('opt-notInstalled') else ""#-->:</span>
<input class="radio" type="checkbox" name="ssl" value="1" <!--#if int($have_ssl) == 0 then "disabled" else ""#-->></label> <input class="radio" type="checkbox" name="ssl" value="1" <!--#if int($have_ssl) == 0 then "disabled" else ""#-->></label>
<br class="clear" /> <br class="clear" />

4
sabnzbd/config.py

@ -344,6 +344,7 @@ class ConfigServer(object):
self.ssl = OptionBool(name, 'ssl', False, add=False) self.ssl = OptionBool(name, 'ssl', False, add=False)
self.enable = OptionBool(name, 'enable', True, add=False) self.enable = OptionBool(name, 'enable', True, add=False)
self.optional = OptionBool(name, 'optional', False, add=False) self.optional = OptionBool(name, 'optional', False, add=False)
self.retention = OptionNumber(name, 'retention', add=False)
self.set_dict(values) self.set_dict(values)
add_to_database('servers', self.__name, self) add_to_database('servers', self.__name, self)
@ -351,7 +352,7 @@ class ConfigServer(object):
def set_dict(self, values): def set_dict(self, values):
""" Set one or more fields, passed as dictionary """ """ Set one or more fields, passed as dictionary """
for kw in ('host', 'port', 'timeout', 'username', 'password', 'connections', for kw in ('host', 'port', 'timeout', 'username', 'password', 'connections',
'fillserver', 'ssl', 'enable', 'optional'): 'fillserver', 'ssl', 'enable', 'optional', 'retention'):
try: try:
value = values[kw] value = values[kw]
except KeyError: except KeyError:
@ -376,6 +377,7 @@ class ConfigServer(object):
dict['ssl'] = self.ssl() dict['ssl'] = self.ssl()
dict['enable'] = self.enable() dict['enable'] = self.enable()
dict['optional'] = self.optional() dict['optional'] = self.optional()
dict['retention'] = self.retention()
return dict return dict
def delete(self): def delete(self):

20
sabnzbd/downloader.py

@ -22,7 +22,6 @@ sabnzbd.downloader - download engine
import time import time
import select import select
import logging import logging
import datetime
from threading import Thread, RLock from threading import Thread, RLock
from nntplib import NNTPPermanentError from nntplib import NNTPPermanentError
import socket import socket
@ -199,7 +198,7 @@ def active_primaries():
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
class Server(object): class Server(object):
def __init__(self, id, host, port, timeout, threads, fillserver, ssl, username = None, def __init__(self, id, host, port, timeout, threads, fillserver, ssl, username = None,
password = None, optional=False): password = None, optional=False, retention=0):
self.id = id self.id = id
self.newid = None self.newid = None
self.restart = False self.restart = False
@ -210,6 +209,7 @@ class Server(object):
self.fillserver = fillserver self.fillserver = fillserver
self.ssl = ssl self.ssl = ssl
self.optional = optional self.optional = optional
self.retention = retention
self.username = username self.username = username
self.password = password self.password = password
@ -246,7 +246,7 @@ class Server(object):
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
class Downloader(Thread): class Downloader(Thread):
def __init__(self, paused = False): def __init__(self, paused=False):
Thread.__init__(self) Thread.__init__(self)
logging.debug("Initializing downloader/decoder") logging.debug("Initializing downloader/decoder")
@ -307,6 +307,7 @@ class Downloader(Thread):
username = srv.username() username = srv.username()
password = srv.password() password = srv.password()
optional = srv.optional() optional = srv.optional()
retention = float(srv.retention() * 24 * 3600) # days ==> seconds
create = True create = True
if oldserver: if oldserver:
@ -321,7 +322,7 @@ class Downloader(Thread):
if create and enabled and host and port and threads: if create and enabled and host and port and threads:
self.servers.append(Server(newserver, host, port, timeout, threads, fillserver, ssl, self.servers.append(Server(newserver, host, port, timeout, threads, fillserver, ssl,
username, password, optional)) username, password, optional, retention))
return primary return primary
@ -401,6 +402,7 @@ class Downloader(Thread):
while 1: while 1:
for server in self.servers: for server in self.servers:
assert isinstance(server, Server)
for nw in server.busy_threads[:]: for nw in server.busy_threads[:]:
if nw.nntp.error_msg or (nw.timeout and time.time() > nw.timeout): if nw.nntp.error_msg or (nw.timeout and time.time() > nw.timeout):
if nw.nntp.error_msg: if nw.nntp.error_msg:
@ -424,6 +426,7 @@ class Downloader(Thread):
# Restart pending, don't add new articles # Restart pending, don't add new articles
continue continue
assert isinstance(server, Server)
if not server.idle_threads or server.restart or self.is_paused() or self.shutdown or self.delayed or self.postproc: if not server.idle_threads or server.restart or self.is_paused() or self.shutdown or self.delayed or self.postproc:
continue continue
@ -431,6 +434,7 @@ class Downloader(Thread):
continue continue
for nw in server.idle_threads[:]: for nw in server.idle_threads[:]:
assert isinstance(nw, NewsWrapper)
if nw.timeout: if nw.timeout:
if time.time() < nw.timeout: if time.time() < nw.timeout:
continue continue
@ -450,7 +454,13 @@ class Downloader(Thread):
if not article: if not article:
break break
else: if server.retention and article.nzf.nzo.avg_stamp < time.time() - server.retention:
# Article too old for the server, treat as missing
if sabnzbd.LOG_ALL:
logging.debug('Article %s too old for %s:%s', article.article, server.host, server.port)
self.decoder.decode(article, None)
break
server.idle_threads.remove(nw) server.idle_threads.remove(nw)
server.busy_threads.append(nw) server.busy_threads.append(nw)

10
sabnzbd/nzbqueue.py

@ -54,7 +54,7 @@ class NzbQueue(TryList):
def __init__(self): def __init__(self):
TryList.__init__(self) TryList.__init__(self)
self.__top_only = cfg.top_only() self.__top_only = False #cfg.top_only()
self.__top_nzo = None self.__top_nzo = None
self.__nzo_list = [] self.__nzo_list = []
@ -195,6 +195,7 @@ class NzbQueue(TryList):
@synchronized(NZBQUEUE_LOCK) @synchronized(NZBQUEUE_LOCK)
def insert_future(self, future, filename, msgid, data, pp=None, script=None, cat=None, priority=NORMAL_PRIORITY, nzbname=None, nzo_info=None): def insert_future(self, future, filename, msgid, data, pp=None, script=None, cat=None, priority=NORMAL_PRIORITY, nzbname=None, nzo_info=None):
""" Refresh a placeholder nzo with an actual nzo """ """ Refresh a placeholder nzo with an actual nzo """
assert isinstance(future, NzbObject)
if nzo_info is None: if nzo_info is None:
nzo_info = {} nzo_info = {}
nzo_id = future.nzo_id nzo_id = future.nzo_id
@ -276,6 +277,7 @@ class NzbQueue(TryList):
@synchronized(NZBQUEUE_LOCK) @synchronized(NZBQUEUE_LOCK)
def add(self, nzo, save=True): def add(self, nzo, save=True):
assert isinstance(nzo, NzbObject)
sabnzbd.QUEUECOMPLETEACTION_GO = False sabnzbd.QUEUECOMPLETEACTION_GO = False
if not nzo.nzo_id: if not nzo.nzo_id:
@ -729,12 +731,6 @@ class NzbQueue(TryList):
ArticleCache.do.purge_articles(nzo.saved_articles) ArticleCache.do.purge_articles(nzo.saved_articles)
@synchronized(NZBQUEUE_LOCK)
def debug(self):
return ([], self.__nzo_list[:],
self.__nzo_table.copy(), self.try_list[:])
def get_urls(self): def get_urls(self):
""" Return list of future-types needing URL """ """ Return list of future-types needing URL """
lst = [] lst = []

6
sabnzbd/nzbstuff.py

@ -87,6 +87,7 @@ class Article(TryList):
if not self.fetcher and not self.server_in_try_list(server): if not self.fetcher and not self.server_in_try_list(server):
self.fetcher = server self.fetcher = server
return self return self
return None
def get_art_id(self): def get_art_id(self):
""" Return unique article storage name, create if needed """ """ Return unique article storage name, create if needed """
@ -420,6 +421,7 @@ class NzbParser(xml.sax.handler.ContentHandler):
""" End of the file """ """ End of the file """
self.nzo.groups = self.groups self.nzo.groups = self.groups
files = max(1, self.valids) files = max(1, self.valids)
self.nzo.avg_stamp = self.avg_age / files
self.nzo.avg_date = datetime.datetime.fromtimestamp(self.avg_age / files) self.nzo.avg_date = datetime.datetime.fromtimestamp(self.avg_age / files)
if self.skipped_files: if self.skipped_files:
logging.warning(Ta('Failed to import %s files from %s'), logging.warning(Ta('Failed to import %s files from %s'),
@ -524,6 +526,7 @@ class NzbObject(TryList):
self.url = '' self.url = ''
self.groups = [] self.groups = []
self.avg_date = datetime.datetime.fromtimestamp(0.0) self.avg_date = datetime.datetime.fromtimestamp(0.0)
self.avg_stamp = 0.0 # Avg age in seconds (calculated from avg_age)
self.dirprefix = [] self.dirprefix = []
self.partable = {} # Holds one parfile-name for each set self.partable = {} # Holds one parfile-name for each set
@ -814,6 +817,7 @@ class NzbObject(TryList):
# Flag files from NZB that already exist as finished # Flag files from NZB that already exist as finished
for nzf in self.files[:]: for nzf in self.files[:]:
alleged_name = nzf.filename alleged_name = nzf.filename
filename = alleged_name
subject = sanitize_filename(latin1(nzf.subject)) subject = sanitize_filename(latin1(nzf.subject))
ready = alleged_name in files ready = alleged_name in files
if not ready: if not ready:
@ -923,6 +927,7 @@ class NzbObject(TryList):
nzf_remove_list = [] nzf_remove_list = []
for nzf in self.files: for nzf in self.files:
assert isinstance(nzf, NzbFile)
# Don't try to get an article if server is in try_list of nzf # Don't try to get an article if server is in try_list of nzf
if not nzf.server_in_try_list(server): if not nzf.server_in_try_list(server):
if not nzf.import_finished: if not nzf.import_finished:
@ -1192,6 +1197,7 @@ class NzbObject(TryList):
# Handle new attributes # Handle new attributes
self.__dict__[tup[1]] = None self.__dict__[tup[1]] = None
self.pp_active = False self.pp_active = False
self.avg_stamp = time.mktime(self.avg_date.timetuple())
TryList.__init__(self) TryList.__init__(self)

3
sabnzbd/skintext.py

@ -69,6 +69,8 @@ SKIN_TEXT = {
'minutes' : TT('mins'), 'minutes' : TT('mins'),
'second' : TT('sec'), 'second' : TT('sec'),
'seconds' : TT('seconds'), 'seconds' : TT('seconds'),
'day' : TT('day'),
'days' : TT('days'),
'month' : TT('Month'), 'month' : TT('Month'),
'year' : TT('Year'), 'year' : TT('Year'),
'daily' : TT('Daily'), 'daily' : TT('Daily'),
@ -377,6 +379,7 @@ SKIN_TEXT = {
'srv-password' : TT('Password'), 'srv-password' : TT('Password'),
'srv-timeout' : TT('Timeout'), 'srv-timeout' : TT('Timeout'),
'srv-connections' : TT('Connections'), 'srv-connections' : TT('Connections'),
'srv-retention' : TT('Retention time'),
'srv-ssl' : TT('SSL'), 'srv-ssl' : TT('SSL'),
'srv-fillserver' : TT('Backup server'), 'srv-fillserver' : TT('Backup server'),
'srv-optional' : TT('Optional'), 'srv-optional' : TT('Optional'),

Loading…
Cancel
Save