053692nd since April 04, 2007
Xicheng's web log
----- a place to make mistakes and learn from scratch
1 -
4 of
totally 15
entries
in
Oct, 2007 found
Next »
Oct 31, 2007 ( Wednesday )
( 255 )
Apache::Session::File
Apache::Session::File is now in use to control the site sessions. It is probably not as fast as using process memory but I think more reliable and safer. Considering multiple people access the same session hash in the shared process memory at the same time, the data will probably be corrupted in the memory, while with Apache::Session::File, this won't happen although it is probably not as transparent as a real database. (You probably can use IPC::Share* to do the same tied things on the session though)
To implement Apache::Session::File, the following code was added in the top-most autohandler:
<%once>
my %opts = (
Directory => '/path/to/tmp/sessions',
LockDirectory => '/path/to/lock/sessions',
);
</%once>
<%init>
## process to grab infor for guest and save it in $session{ $session_id }
my $session_id = myweb_get_cookie('U');
eval { tie %session, 'Apache::Session::File', $session_id, \%opts };
if ( $@ ) {
# create a new session if there is no session in the store:
if ( $@ =~ /^Object does not exist/ ) {
eval { tie %session, 'Apache::Session::File', undef, \%opts };
$session_id = $session{_session_id};
# initialize a session
$session{ $session_id }{key} = 'value';
$session{update} = time;
eval { untie %session };
myweb_send_cookie('U', $session_id);
} else {
# Faked or bad sessions - bail out:
$m->redirect('/lib/bad_session.html');
}
}
Something need to know:
1) A global variable %session is defined in mason.fcgi(or httpd.conf, startup.pl), so I don't have to tie the session store each time I want to read/write the session.
2) Because of the lock and unlock mechanism used in Apache::Session::File, you have to untie the session hash whenever you finish writing it, otherwise the process might be in deadlock which immediately eats up your system resources (be careful). I was trapped in this trouble many times when I first tried Apache::Session::File.:(
3) Apache::Session checks only the first level data structure, so if $session{$id}{color} changed, Apache::Session wont noticed that. A rescue is to assign a top-level key (i.e. $session{update} = time) whenever you update the session hash
4) You get a new session when session_id is undef, and extract session info if the session_id exists. Apache::Session::File help you get a session_key when you tied a new session hash, and the id can be accessed through the key '_session_id' of that hash
5) All session files are saved under the 'Directory' specified in %opts, and named with the session_id. the similar to the session lock files.
Apache::Session::File is a light-weight session manage engine, it might not be easy to implement, but very convenient to manage, the following is a script I used to control number of files under a directory which can be put in a crontab job to manage the session and session-lock files from outside the HTTP server...
#!/bin/sh
# bash script to limit the maximum number of files under a $dir
# and remove old files according to their modification time.
# Usage clean.sh dirname 20 # keep only 20 files under dirname
num=${1:-100}
dir=${2:-/path/to/tmp/sessions}
cd "$dir"
command ls -rt | \
perl -se '
@x = <>;
map { print "rm -f $d/$_"} @x[0..@x-$n] if @x > $n
' -- -n="$num" -d="$dir" | sh ...More
To implement Apache::Session::File, the following code was added in the top-most autohandler:
<%once>
my %opts = (
Directory => '/path/to/tmp/sessions',
LockDirectory => '/path/to/lock/sessions',
);
</%once>
<%init>
## process to grab infor for guest and save it in $session{ $session_id }
my $session_id = myweb_get_cookie('U');
eval { tie %session, 'Apache::Session::File', $session_id, \%opts };
if ( $@ ) {
# create a new session if there is no session in the store:
if ( $@ =~ /^Object does not exist/ ) {
eval { tie %session, 'Apache::Session::File', undef, \%opts };
$session_id = $session{_session_id};
# initialize a session
$session{ $session_id }{key} = 'value';
$session{update} = time;
eval { untie %session };
myweb_send_cookie('U', $session_id);
} else {
# Faked or bad sessions - bail out:
$m->redirect('/lib/bad_session.html');
}
}
Something need to know:
1) A global variable %session is defined in mason.fcgi(or httpd.conf, startup.pl), so I don't have to tie the session store each time I want to read/write the session.
2) Because of the lock and unlock mechanism used in Apache::Session::File, you have to untie the session hash whenever you finish writing it, otherwise the process might be in deadlock which immediately eats up your system resources (be careful). I was trapped in this trouble many times when I first tried Apache::Session::File.:(
3) Apache::Session checks only the first level data structure, so if $session{$id}{color} changed, Apache::Session wont noticed that. A rescue is to assign a top-level key (i.e. $session{update} = time) whenever you update the session hash
4) You get a new session when session_id is undef, and extract session info if the session_id exists. Apache::Session::File help you get a session_key when you tied a new session hash, and the id can be accessed through the key '_session_id' of that hash
5) All session files are saved under the 'Directory' specified in %opts, and named with the session_id. the similar to the session lock files.
Apache::Session::File is a light-weight session manage engine, it might not be easy to implement, but very convenient to manage, the following is a script I used to control number of files under a directory which can be put in a crontab job to manage the session and session-lock files from outside the HTTP server...
#!/bin/sh
# bash script to limit the maximum number of files under a $dir
# and remove old files according to their modification time.
# Usage clean.sh dirname 20 # keep only 20 files under dirname
num=${1:-100}
dir=${2:-/path/to/tmp/sessions}
cd "$dir"
command ls -rt | \
perl -se '
@x = <>;
map { print "rm -f $d/$_"} @x[0..@x-$n] if @x > $n
' -- -n="$num" -d="$dir" | sh ...More
Oct 28, 2007 ( Sunday )
( 415 )
use JSON
Here comes an improved AJAX implememtation of the click-to-expand Blog entry bars, see my previous post Added a new feature with AJAX.. And now JSON is used to better help the client-to-server communications.
JSON as for AJAX is actually a data serialization tool that deliver and convert data between Javascript code and the server-side code. Before I had JSON, an AJAX request usually bring back only one bulk text from the server-side, and I can then use innerHTML to insert the text into a single 'named' container(i.e. an <div /> element).. With JSON, instead of a raw string, I get a perfect Javascript data-structure by a minor adjustment, say
Previously:
if ((oXHR.readyState == 4) && (oXHR.status == 200))
obj.innerHTML = oXHR.responseText;
and now:
if ((oXHR.readyState == 4) && (oXHR.status == 200)) {
var aJson = oXHR.responseText.parseJSON();
oContent.innerHTML = aJson.content;
oCount.innerHTML = aJson.count;
........
}
;
Now I dont have to insert all the text into one <div />, with a data structure, I can insert my text into multiple separate containers, with which I can fine control the data grabbed from the server-side within just one AJAX call...
on the server-side, I have HTML::Mason and an JSON Perl module. All are very easy to be implemented...:-) ...More
JSON as for AJAX is actually a data serialization tool that deliver and convert data between Javascript code and the server-side code. Before I had JSON, an AJAX request usually bring back only one bulk text from the server-side, and I can then use innerHTML to insert the text into a single 'named' container(i.e. an <div /> element).. With JSON, instead of a raw string, I get a perfect Javascript data-structure by a minor adjustment, say
Previously:
if ((oXHR.readyState == 4) && (oXHR.status == 200))
obj.innerHTML = oXHR.responseText;
and now:
if ((oXHR.readyState == 4) && (oXHR.status == 200)) {
var aJson = oXHR.responseText.parseJSON();
oContent.innerHTML = aJson.content;
oCount.innerHTML = aJson.count;
........
}
;
Now I dont have to insert all the text into one <div />, with a data structure, I can insert my text into multiple separate containers, with which I can fine control the data grabbed from the server-side within just one AJAX call...
on the server-side, I have HTML::Mason and an JSON Perl module. All are very easy to be implemented...:-) ...More
Oct 27, 2007 ( Saturday )
( 197 )
A book to recommend
Oct 27, 2007 ( Saturday )
( 334 )
About Cache (new update)
Mason has very flexible Cache control which might be one of the most attractive things among various Web development tools. I just put all the auto-updating data in "Monthly Archives", "Latest comments", "Most hits" and "Top keywords" into Mason's cache spaces.(FileCache by default, which can always be found at Mason's data_dir.).
So, for example, for "Top keywords" and "Most hits", I maintained a stack and check it on every updating operation of the database and pop out the key with smallest count..This way, instead of communicating with DB, I can grab data directly from the Mason cached space. Although MySQL itself should also have its Caching mechanism. I am hoping this caching could be better, not sure how much performance improvement I can get from this though..
One thing must be noticed is that Mason's cache is based on the current component, so if you want to get or update cached values from other components, you have to do something more.. Here is a function I used for grabbing the caches of another Mason component.:
sub myweb_get_cache_obj
{
my $component = shift;
return if not $component;
require HTML::Mason::Utils;
return new Cache::FileCache({
namespace => HTML::Mason::Utils::data_cache_namespace( $component ),
cache_root => "/path/to/mason/data_dir/cache",
}) || undef;
}
And in my component to update the DB, I added:
my $cache = myweb_get_cache_obj('/path/to/update.mas');
my $session_example = $cache->get('_session_example') ?
$cache->get('_session_example') : undef;
if (defined $session_example) {
myapp_update_stack(
$session_example,
[ $count, $new_example ]
);
$cache->set('_session_example', $session_example);
}
This works pretty well so far...:-) ...More
So, for example, for "Top keywords" and "Most hits", I maintained a stack and check it on every updating operation of the database and pop out the key with smallest count..This way, instead of communicating with DB, I can grab data directly from the Mason cached space. Although MySQL itself should also have its Caching mechanism. I am hoping this caching could be better, not sure how much performance improvement I can get from this though..
One thing must be noticed is that Mason's cache is based on the current component, so if you want to get or update cached values from other components, you have to do something more.. Here is a function I used for grabbing the caches of another Mason component.:
sub myweb_get_cache_obj
{
my $component = shift;
return if not $component;
require HTML::Mason::Utils;
return new Cache::FileCache({
namespace => HTML::Mason::Utils::data_cache_namespace( $component ),
cache_root => "/path/to/mason/data_dir/cache",
}) || undef;
}
And in my component to update the DB, I added:
my $cache = myweb_get_cache_obj('/path/to/update.mas');
my $session_example = $cache->get('_session_example') ?
$cache->get('_session_example') : undef;
if (defined $session_example) {
myapp_update_stack(
$session_example,
[ $count, $new_example ]
);
$cache->set('_session_example', $session_example);
}
This works pretty well so far...:-) ...More
| More entries: 1 2 3 4 Next » | End |
[ Previous Page ] | [ Blog Main ]
Monthly archives
Site Statistics
Newest comments
My links
Add new links
Advanced Search
Blog

