openSUSE:WebYaST Caching
WebYaST Caching
How it works
The last view releases have shown that the backend of WebYaST is too slow. Especially starting new modules takes very often too much time.
A system management tools is based on data which will not be changed very often ( e.g. user, printer, network settings) but consumes very much time for evaluating. So the idea is to preload this data while starting WebYaST in a cache which can be used at once.
If the cache is used by the UI a job will be started parallel to evaluate this data again from the system. If the new evaluated data differs from the cache the UI/user will be informed and the UI will be reloaded:
WebYaST | http-communication | HTTP browser |
---|---|---|
* starting with: rcwebyast start | ||
* Go through all models, calls the find methods, and insert the results into the cache: User.find(:all) Network.find(:all) Ldap.find(:all) ... .. . |
||
* Showing e.g. the User' index page | ||
<--- GET User/ --- | * Getting all Users from WebYaST | |
* Reading Cache for User.find(:all) | --- User.find(:all) ---> | * Showing all Users in the UI |
* Calling User.find(:all) in order to check and update cache. | ||
<--- GET notifier/user --- | * Polling if the cache has been changed meanwhile. | |
* Check if the User cache has been changed ? | --- yes/no --> | * Update UI if the date has been changed meanwhile |
* Polling for changed cache periodically ... .. . |
The nice "side-effect" is that other UIs will also be informed if some data has been changed in the background meanwhile. E.g. two users edit the network configuration at the same time. After one user has saved his values the second user will be informed that the data has been changed and he will get an update.
How it is implemented
If you want to use this cache mechanism in your plugin you have to change following methods in your model class. This is an example for the Group model class (file: plugins/users/app/models/group.rb):
require 'yast_service'
Includes needed libs.
def self.find (cn) return find_all if cn == :all YastCache.fetch(self, cn) { result = group_get( "system", cn ) result = group_get( "local", cn ) if result.empty? return nil if result.empty? make_group result } end def self.find_all YastCache.fetch(self, :all) { result = groups_get "local" result.update( groups_get "system") result_array = [] result.each { |k,v| result_array << make_group(v) } result_array.sort! {|x,y| x.cn <=> y.cn} }
YastCache.fetch(self, cn) and YastCache.fetch(self, :all) reads the groups cache with the id cn or :all. If it is empty the given code block will be executed and the evaluated value will be inserted into the cache and will be returned.
def save existing_group = Group.group_get( group_type, old_cn ) if existing_group.empty? result = YastService.Call( "YaPI::USERS::GroupAdd", { "type" => ["s", group_type] }, { "cn" => ["s",cn], "userlist" => ["as", members] } ) else result = YastService.Call( "YaPI::USERS::GroupModify", { "type" => ["s", group_type], "cn" => ["s", old_cn] }, { "gidNumber" => ["i", gid], "cn" => ["s",cn], "userlist" => ["as", members] } ) end YastCache.reset(self, old_cn) result # result is empty string on success, error message otherwise end
With YastCache.reset(self, old_cn) the cache becomes invalid and will be filled up again in the background.
def destroy existing_group = Group.group_get( group_type, old_cn ) if existing_group.empty? ret = "" else ret = YastService.Call( "YaPI::USERS::GroupDelete", {"type" => ["s",group_type], "cn" => ["s",old_cn]}) end YastCache.delete(self,old_cn) ret end
YastCache.delete(self,old_cn) deletes the cache for that group.