diff --git a/ChangeLog b/ChangeLog
index fc147202f..ce6e267aa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -15,6 +15,7 @@
* Add an error category to the tracker sidebar list
* Add Find More Plugins button to Plugins preference page
* Fix #518 remove header in add torrent dialog to save vertical space
+ * Add a Cache preferences page to adjust cache settings and examine cache status
==== ConsoleUI ====
* Changed to use curses for a more interactive client
diff --git a/deluge/core/core.py b/deluge/core/core.py
index fee3b9d48..f41a5a3bb 100644
--- a/deluge/core/core.py
+++ b/deluge/core/core.py
@@ -337,6 +337,35 @@ class Core(component.Component):
return status
+ @export
+ def get_cache_status(self):
+ """
+ Returns a dictionary of the session's cache status.
+
+ :returns: a dict of the cache status
+
+ """
+
+ status = self.session.get_cache_status()
+ cache = {}
+ for attr in dir(status):
+ if attr.startswith("_"):
+ continue
+ cache[attr] = getattr(status, attr)
+
+ # Add in a couple ratios
+ try:
+ cache["write_hit_ratio"] = float((cache["blocks_written"] - cache["writes"])) / float(cache["blocks_written"])
+ except ZeroDivisionError:
+ cache["write_hit_ratio"] = 0.0
+
+ try:
+ cache["read_hit_ratio"] = float(cache["blocks_read_hit"]) / float(cache["blocks_read"])
+ except ZeroDivisionError:
+ cache["read_hit_ratio"] = 0.0
+
+ return cache
+
@export
def force_reannounce(self, torrent_ids):
log.debug("Forcing reannouncment to: %s", torrent_ids)
diff --git a/deluge/core/preferencesmanager.py b/deluge/core/preferencesmanager.py
index b2c0d193b..f249d5cc0 100644
--- a/deluge/core/preferencesmanager.py
+++ b/deluge/core/preferencesmanager.py
@@ -144,7 +144,9 @@ DEFAULT_PREFS = {
"random_outgoing_ports": True,
"peer_tos": "0x00",
"rate_limit_ip_overhead": True,
- "geoip_db_location": "/usr/share/GeoIP/GeoIP.dat"
+ "geoip_db_location": "/usr/share/GeoIP/GeoIP.dat",
+ "cache_size": 512,
+ "cache_expiry": 60
}
class PreferencesManager(component.Component):
@@ -227,6 +229,10 @@ class PreferencesManager(component.Component):
self._on_rate_limit_ip_overhead)
self.config.register_set_function("geoip_db_location",
self._on_geoip_db_location)
+ self.config.register_set_function("cache_size",
+ self._on_cache_size)
+ self.config.register_set_function("cache_expiry",
+ self._on_cache_expiry)
self.config.register_change_callback(self._on_config_value_change)
@@ -516,3 +522,13 @@ class PreferencesManager(component.Component):
except Exception, e:
log.error("Unable to load geoip database!")
log.exception(e)
+
+ def _on_cache_size(self, key, value):
+ log.debug("%s: %s", key, value)
+ self.settings.cache_size = value
+ self.session.set_settings(self.settings)
+
+ def _on_cache_expiry(self, key, value):
+ log.debug("%s: %s", key, value)
+ self.settings.cache_expiry = value
+ self.session.set_settings(self.settings)
diff --git a/deluge/ui/gtkui/glade/preferences_dialog.glade b/deluge/ui/gtkui/glade/preferences_dialog.glade
index 964b6ee59..93203d504 100644
--- a/deluge/ui/gtkui/glade/preferences_dialog.glade
+++ b/deluge/ui/gtkui/glade/preferences_dialog.glade
@@ -4282,6 +4282,554 @@ HTTP W/ Auth
tab
+
+
+ True
+ True
+ automatic
+ automatic
+
+
+ True
+ queue
+ none
+
+
+ True
+ vertical
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 0
+ 10
+ 10
+ <b><i><big>Cache</big></i></b>
+ True
+
+
+ False
+ 0
+
+
+
+
+ True
+
+
+ False
+ 1
+
+
+
+
+ True
+ 12
+
+
+ True
+ vertical
+
+
+ True
+ 0
+ none
+
+
+ True
+ 5
+ 12
+
+
+ True
+ 2
+ 2
+ 5
+
+
+ True
+ 0
+ Cache Size (16 KiB blocks):
+
+
+ GTK_FILL
+
+
+
+
+ True
+ True
+ The number of seconds from the last cached write to a piece in the write cache, to when it's forcefully flushed to disk. Default is 60 seconds.
+ 0
+ Cache Expiry (seconds):
+
+
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ True
+ ●
+ 1
+ 512 0 99999 1 10 10
+ True
+ if-valid
+
+
+ 1
+ 2
+
+
+
+
+
+ True
+ True
+ 5
+ ●
+ 5
+ 1
+ 60 1 32000 1 10 10
+
+
+ 1
+ 2
+ 1
+ 2
+
+
+
+
+
+
+
+
+
+ True
+ <b>Settings</b>
+ True
+
+
+ label_item
+
+
+
+
+ False
+ False
+ 5
+ 0
+
+
+
+
+ True
+ 0
+ none
+
+
+ True
+ 5
+ 12
+
+
+ True
+ vertical
+
+
+ True
+ 0
+ none
+
+
+ True
+ 12
+
+
+ True
+ 3
+ 2
+ 5
+
+
+ True
+ The total number of 16 KiB blocks written to disk since this session was started.
+ 0
+ Blocks Written:
+
+
+ GTK_FILL
+
+
+
+
+ True
+ The total number of write operations performed since this session was started.
+ 0
+ Writes:
+
+
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ The ratio (blocks_written - writes) / blocks_written represents the number of saved write operations per total write operations, i.e. a kind of cache hit ratio for the write cache.
+ 0
+ Write Cache Hit Ratio:
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ 1
+
+
+ 1
+ 2
+
+
+
+
+
+ True
+ 1
+
+
+ 1
+ 2
+ 1
+ 2
+
+
+
+
+
+ True
+ 1
+
+
+ 1
+ 2
+ 2
+ 3
+
+
+
+
+
+
+
+
+
+ True
+ <b>Write</b>
+ True
+
+
+ label_item
+
+
+
+
+ 0
+
+
+
+
+ True
+ 0
+ none
+
+
+ True
+ 12
+
+
+ True
+ 4
+ 2
+ 5
+
+
+ True
+ The number of blocks that were requested from the bittorrent engine (from peers), that were served from disk or cache.
+ 0
+ Blocks Read:
+
+
+ GTK_FILL
+
+
+
+
+ True
+ The number of blocks that were served from cache.
+ 0
+ Blocks Read Hit:
+
+
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ The cache hit ratio for the read cache.
+ 0
+ Read Cache Hit Ratio:
+
+
+ 3
+ 4
+ GTK_FILL
+
+
+
+
+ True
+ 1
+
+
+ 1
+ 2
+
+
+
+
+
+ True
+ 1
+
+
+ 1
+ 2
+ 1
+ 2
+
+
+
+
+
+ True
+ 1
+
+
+ 1
+ 2
+ 3
+ 4
+
+
+
+
+
+ True
+ True
+ The total number of read operations performed since this session was started.
+ 0
+ Reads:
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+
+
+ 1
+ 2
+ 2
+ 3
+
+
+
+
+
+
+
+
+
+ True
+ <b>Read</b>
+ True
+
+
+ label_item
+
+
+
+
+ 1
+
+
+
+
+ True
+ 0
+ none
+
+
+ True
+ 12
+
+
+ True
+ 2
+ 2
+ 5
+
+
+ True
+ The number of 16 KiB blocks currently in the disk cache. This includes both read and write cache.
+ 0
+ Cache Size:
+
+
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Read Cache Size:
+
+
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ 1
+
+
+ 1
+ 2
+
+
+
+
+
+ True
+ 1
+
+
+ 1
+ 2
+ 1
+ 2
+
+
+
+
+
+
+
+
+
+ True
+ <b>Size</b>
+ True
+
+
+ label_item
+
+
+
+
+ 2
+
+
+
+
+ True
+ start
+
+
+ gtk-refresh
+ True
+ True
+ True
+ True
+
+
+
+ False
+ False
+ 0
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+ True
+ <b>Status</b>
+ True
+
+
+ label_item
+
+
+
+
+ False
+ False
+ 5
+ 1
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 9
+
+
+
+
+
+ tab
+
+
True
@@ -4687,7 +5235,7 @@ HTTP W/ Auth
- 9
+ 10
@@ -4696,15 +5244,6 @@ HTTP W/ Auth
tab
-
-
-
-
-
-
- tab
-
-
True
diff --git a/deluge/ui/gtkui/preferences.py b/deluge/ui/gtkui/preferences.py
index b6e2328ff..e9f4f83c3 100644
--- a/deluge/ui/gtkui/preferences.py
+++ b/deluge/ui/gtkui/preferences.py
@@ -69,7 +69,8 @@ class Preferences(component.Component):
# Add the default categories
i = 0
for category in [_("Downloads"), _("Network"), _("Bandwidth"), _("Interface"),
- _("Other"), _("Daemon"), _("Queue"), _("Proxy"), _("Notification"), _("Plugins")]:
+ _("Other"), _("Daemon"), _("Queue"), _("Proxy"), _("Notification"),
+ _("Cache"), _("Plugins")]:
self.liststore.append([i, category])
i += 1
@@ -188,6 +189,10 @@ class Preferences(component.Component):
def _on_get_listen_port(port):
self.active_port = port
+ client.core.get_cache_status().addCallback(_on_get_cache_status)
+
+ def _on_get_cache_status(status):
+ self.cache_status = status
self._show()
# This starts a series of client.core requests prior to showing the window
@@ -281,6 +286,8 @@ class Preferences(component.Component):
"chk_seed_ratio": ("active", self.core_config["stop_seed_at_ratio"]),
"spin_share_ratio": ("value", self.core_config["stop_seed_ratio"]),
"chk_remove_ratio": ("active", self.core_config["remove_seed_at_ratio"]),
+ "spin_cache_size": ("value", self.core_config["cache_size"]),
+ "spin_cache_expiry": ("value", self.core_config["cache_expiry"])
}
# Add proxy stuff
for t in ("peer", "web_seed", "tracker", "dht"):
@@ -409,6 +416,8 @@ class Preferences(component.Component):
"spin_share_ratio_limit",
"spin_seed_time_ratio_limit",
"spin_seed_time_limit",
+ "spin_cache_size",
+ "spin_cache_expiry"
]
for t in ("peer", "web_seed", "tracker", "dht"):
core_widget_list.append("spin_proxy_port_%s" % t)
@@ -478,6 +487,9 @@ class Preferences(component.Component):
elif self.gtkui_config["ntf_security"] == 'TLS':
self.glade.get_widget("rad_ntf_tls").set_active(True)
+ ## Cache tab ##
+ self.__update_cache_status()
+
## Plugins tab ##
all_plugins = self.all_plugins
enabled_plugins = self.enabled_plugins
@@ -754,6 +766,25 @@ class Preferences(component.Component):
def hide(self):
self.pref_dialog.hide()
+ def __update_cache_status(self):
+ # Updates the cache status labels with the info in the dict
+ for widget in self.glade.get_widget_prefix("label_cache_"):
+ key = widget.get_name()[len("label_cache_"):]
+ value = self.cache_status[key]
+ if type(value) == float:
+ value = "%.2f" % value
+ else:
+ value = str(value)
+
+ widget.set_text(value)
+
+ def on_button_cache_refresh_clicked(self, widget):
+ def on_get_cache_status(status):
+ self.cache_status = status
+ self.__update_cache_status()
+
+ client.core.get_cache_status().addCallback(on_get_cache_status)
+
def on_pref_dialog_delete_event(self, widget, event):
self.hide()
return True