# # Copyright (C) 2008 Alexandros Stergiakis <sterg@kth.se> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # #//# # Persistent storage across reboots. It relies on distribution-specific event handlers that # will copy the data to persistent storage, except if the STORAGE_FILE already resides in # a persistent directory. File is always restored on boot. Data are accessed as an array. # # We refer to this persistent storage as Storage. The Storage is appropriate for information # that are not suitable for the main conf, such as time of last log-in, reason of last reboot, # log-in history, failed login attempts, and other casual information that are not part of # the router configuration as such. # # Warning: # Notice that this Storage facility is only for the Master Interpreter/Thread. It is not meant # to be used for concurrent use by Master and Session threads/interp. # # @changelog # * # # @copyright 2007-2008 Alexandros Stergiakis <alsterg@gmail.com> # @author Alexandros Stergiakis <alsterg@gmail.com> #//# namespace eval storage { namespace import ::helper::writefile ::helper::readfile namespace export load unload # Global: array set ::Storage {} variable loaded 0 variable lastjob 0 # Invoked with a trace when-ever Storage is modified. # @assume storage::load is executed before. proc update {args} { global Storage variable lastjob if {[catch {after info $lastjob}]} { ;# No pending job Global STORAGE_FILE # XXX Use mmap (remove trace) writefile $STORAGE_FILE [array get Storage] # Emitted after persistent storage gets modified. This event is rate limitted. set lastjob [after 10000 [list event emit PERSISTENT_STORAGE_UPDATE]] ;# (@magic-number) # A handler attached to this event can be used to take care of copying the # Storage File (STORAGE_FILE) to a safe place after a modification is done. # It can also be used to monitor specific variables within Storage. } } # Loads stored information from last boot in the global namespace as an array named "Storage". # Access to the Storage array can then be done as usual with the "global" command. proc load {} { global Storage variable loaded variable lastjob if {$loaded} { return } Global STORAGE_FILE array set Storage [readfile $STORAGE_FILE] set loaded 1 # Note: Write variable trace is called after the variable/array is modified trace add variable ::Storage write ::storage::update } # Unloads Storage from the global namespace and invokes "update" to save it. # Access with the "global" command will not be possible after this. proc unload {} { global Storage variable loaded variable lastjob if {! $loaded} { return } if {! [catch {after info $lastjob}]} { ;# Pending job after cancel $lastjob event emit PERSISTENT_STORAGE_UPDATE } set lastjob 0 trace remove variable ::Storage write ::storage::update unset Storage set loaded 0 } namespace ensemble create } ;# End of Namespace