From 7c1bf3d258320cedf4c4147edc83432bada8418d Mon Sep 17 00:00:00 2001 From: Nigel Kukard <nkukard@lbsd.net> Date: Sun, 16 Nov 2008 07:56:16 +0000 Subject: [PATCH] * Added caching engine * Added database engine --- smradius/cache.pm | 218 ++++++++++++++++++++++++++ smradius/dbilayer.pm | 359 +++++++++++++++++++++++++++++++++++++++++++ smradius/dblayer.pm | 292 +++++++++++++++++++++++++++++++++++ 3 files changed, 869 insertions(+) create mode 100644 smradius/cache.pm create mode 100644 smradius/dbilayer.pm create mode 100644 smradius/dblayer.pm diff --git a/smradius/cache.pm b/smradius/cache.pm new file mode 100644 index 00000000..2844a141 --- /dev/null +++ b/smradius/cache.pm @@ -0,0 +1,218 @@ +# Caching engine +# Copyright (C) 2007 Nigel Kukard <nkukard@lbsd.net> +# Copyright (C) 2008, LinuxRulz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +package cbp::cache; + +use strict; +use warnings; + + +require Exporter; +our (@ISA,@EXPORT); +@ISA = qw(Exporter); +@EXPORT = qw( + cacheStoreKeyPair + cacheGetKeyPair +); + +use Cache::FastMmap; + +# Cache stuff +my $cache_type = "FastMmap"; +my $cache; + + +# Our current error message +my $error = ""; + +# Set current error message +# Args: error_message +sub setError +{ + my $err = shift; + my ($package,$filename,$line) = caller; + my (undef,undef,undef,$subroutine) = caller(1); + + # Set error + $error = "$subroutine($line): $err"; +} + +# Return current error message +# Args: none +sub Error +{ + my $err = $error; + + # Reset error + $error = ""; + + # Return error + return $err; +} + + + + + +# Initialize cache +sub Init +{ + my $server = shift; + my $ch; + + + # Create Cache + $ch = Cache::FastMmap->new( + 'page_size' => 2048, + 'num_pages' => 1000, + 'raw_values' => 1, + 'unlink_on_exit' => 1, + ); + + # Stats + $ch->set('Cache/Stats/Hit',0); + $ch->set('Cache/Stats/Miss',0); + + # Set server vars + $server->{'cache_engine'}{'handle'} = $ch; +}; + +# Destroy cache +sub Destroy +{ + my $server = shift; + +}; + +# Connect child to cache +sub connect +{ + my $server = shift; + + $cache = $server->{'cache_engine'}{'handle'}; +} + + +# Disconnect child from cache +sub disconnect +{ + my $server = shift; + +} + + +# Store keypair in cache +# Parameters: +# CacheName - Name of cache we storing things in +# Key - Item key +# Value - Item value +sub cacheStoreKeyPair +{ + my ($cacheName,$key,$value) = @_; + + + if (!defined($cacheName)) { + setError("Cache name not defined in store"); + return -1; + } + + if (!defined($key)) { + setError("Key not defined for cache '$cacheName' store"); + return -1; + } + + if (!defined($value)) { + setError("Value not defined for cache '$cacheName' key '$key' store"); + return -1; + } + + # If we're not caching just return + return 0 if ($cache_type eq 'none'); + + # Store + $cache->set("$cacheName/$key",$value); + + return 0; +} + + +# Get data from key in cache +# Parameters: +# CacheName - Name of cache we storing things in +# Key - Item key +sub cacheGetKeyPair +{ + my ($cacheName,$key) = @_; + + + if (!defined($cacheName)) { + setError("Cache name not defined in get"); + return (-1); + } + + if (!defined($key)) { + setError("Key not defined for cache '$cacheName' get"); + return (-1); + } + + # If we're not caching just return + if ($cache_type eq 'none') { + return (0,undef); + } + + # Check and count + my $res = $cache->get("$cacheName/$key"); + if ($res) { + $cache->get_and_set('Cache/Stats/Hit',sub { return ++$_[1]; }); + } else { + $cache->get_and_set('Cache/Stats/Miss',sub { return ++$_[1]; }); + } + + return (0,$res); +} + + +# Return cache hit ratio +sub getHitRatio +{ + my $res; + + + # Get counter + $res = $cache->get('Cache/Stats/Hit'); + + return $res; +} + + +# Return cache miss ratio +sub getMissRatio +{ + my $res; + + + # Get counter + $res = $cache->get('Cache/Stats/Miss'); + + return $res; +} + + +1; +# vim: ts=4 diff --git a/smradius/dbilayer.pm b/smradius/dbilayer.pm new file mode 100644 index 00000000..7a06fb55 --- /dev/null +++ b/smradius/dbilayer.pm @@ -0,0 +1,359 @@ +# Database independent layer module +# Copyright (C) 2005-2007 Nigel Kukard <nkukard@lbsd.net> +# Copyright (C) 2008, LinuxRulz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + + + +package cbp::dbilayer; + +use strict; +use warnings; + + +use cbp::config; +use DBI; + + + +my $internalError = ""; + + +sub internalErr +{ + my $error = $internalError; + + $internalError = ""; + + return $error; +} + + +# Initialize class and return a fully connected object +sub Init +{ + my $server = shift; + my $dbconfig = $server->{'cbp'}->{'database'}; + + + # Check if we created + my $dbh = cbp::dbilayer->new($dbconfig->{'DSN'},$dbconfig->{'Username'},$dbconfig->{'Password'},$dbconfig->{'TablePrefix'}); + return undef if (!defined($dbh)); + + return $dbh; +} + + +# Constructor +sub new +{ + my ($class,$dsn,$username,$password,$table_prefix) = @_; + + # Iternals + my $self = { + _dbh => undef, + _error => undef, + + _dsn => undef, + _username => undef, + _password => undef, + + _table_prefix => "", + + _in_transaction => undef, + }; + + # Set database parameters + if (defined($dsn)) { + $self->{_dsn} = $dsn; + $self->{_username} = $username; + $self->{_password} = $password; + $self->{_table_prefix} = $table_prefix if (defined($table_prefix) && $table_prefix ne ""); + } else { + $internalError = "Invalid DSN given"; + return undef; + } + + # Create... + bless $self, $class; + return $self; +} + + + +# Return current error message +# Args: none +sub Error +{ + my ($self) = @_; + + my $err = $self->{_error}; + + # Reset error + $self->{_error} = ""; + + # Return error + return $err; +} + + +# Return connection to database +# Args: none +sub connect +{ + my ($self) = @_; + + + $self->{_dbh} = DBI->connect($self->{_dsn}, $self->{_username}, $self->{_password}, { + 'AutoCommit' => 1, + 'PrintError' => 0, + 'FetchHashKeyName' => 'NAME_lc' + }); + + # Connect to database if we have to, check if we ok + if (!$self->{_dbh}) { + $self->{_error} = "Error connecting to database: $DBI::errstr"; + return -1; + } + + # Apon connect we are not in a transaction + $self->{_in_transaction} = 0; + + return 0; +} + + +# Check database connection +# Args: none +sub _check +{ + my $self = shift; + + + # If we not in a transaction try connect + if ($self->{_in_transaction} == 0) { + # Try ping + if (!$self->{_dbh}->ping()) { + # Disconnect & reconnect + $self->{_dbh}->disconnect(); + $self->connect(); + } + } +} + + +# Return database selection results... +# Args: <select statement> +sub select +{ + my ($self,$query,@params) = @_; + + + $self->_check(); + +# # Build single query instead of using binding of params +# # not all databases support binding, and not all support all +# # the places we use ? +# $query =~ s/\?/%s/g; +# # Map each element in params to the quoted value +# $query = sprintf($query, +# map { $self->quote($_) } @params +# ); +#use Data::Dumper; print STDERR Dumper($query); + # Prepare query + my $sth; + if (!($sth = $self->{_dbh}->prepare($query))) { + $self->{_error} = $self->{_dbh}->errstr; + return undef; + } + + # Check for execution error +# if (!$sth->execute()) { + if (!$sth->execute(@params)) { + $self->{_error} = $self->{_dbh}->errstr; + return undef; + } + + return $sth; +} + + +# Perform a command +# Args: <command statement> +sub do +{ + my ($self,$command,@params) = @_; + + + $self->_check(); + +# # Build single command instead of using binding of params +# # not all databases support binding, and not all support all +# # the places we use ? +# $command =~ s/\?/%s/g; +# # Map each element in params to the quoted value +# $command = sprintf($command, +# map { $self->quote($_) } @params +# ); +#use Data::Dumper; print STDERR Dumper($command); + + # Prepare query + my $sth; +# if (!($sth = $self->{_dbh}->do($command))) { + if (!($sth = $self->{_dbh}->do($command,undef,@params))) { + $self->{_error} = $self->{_dbh}->errstr; + return undef; + } + + return $sth; +} + + +# Function to get last insert id +# Args: <table> <column> +sub lastInsertID +{ + my ($self,$table,$column) = @_; + + + # Get last insert id + my $res; + if (!($res = $self->{_dbh}->last_insert_id(undef,undef,$table,$column))) { + $self->{_error} = $self->{_dbh}->errstr; + return undef; + } + + return $res; +} + + +# Function to begin a transaction +# Args: none +sub begin +{ + my ($self) = @_; + + $self->_check(); + + $self->{_in_transaction}++; + + # Don't really start transaction if we more than 1 deep + if ($self->{_in_transaction} > 1) { + return 1; + } + + # Begin + my $res; + if (!($res = $self->{_dbh}->begin_work())) { + $self->{_error} = $self->{_dbh}->errstr; + return undef; + } + + return $res; +} + + +# Function to commit a transaction +# Args: none +sub commit +{ + my ($self) = @_; + + + # Reduce level + $self->{_in_transaction}--; + + # If we not at top level, return success + if ($self->{_in_transaction} > 0) { + return 1; + } + + # Reset transaction depth to 0 + $self->{_in_transaction} = 0; + + # Commit + my $res; + if (!($res = $self->{_dbh}->commit())) { + $self->{_error} = $self->{_dbh}->errstr; + return undef; + } + + return $res; +} + + +# Function to rollback a transaction +# Args: none +sub rollback +{ + my ($self) = @_; + + + # If we at top level, return success + if ($self->{_in_transaction} < 1) { + return 1; + } + + $self->{_in_transaction} = 0; + + # Rollback + my $res; + if (!($res = $self->{_dbh}->rollback())) { + $self->{_error} = $self->{_dbh}->errstr; + return undef; + } + + return $res; +} + + +# Function to quote a database variable +# Args: <stuff to quote> +sub quote +{ + my ($self,$stuff) = @_; + + return $self->{_dbh}->quote($stuff); +} + + +# Function to cleanup DB query +# Args: <sth> +sub free +{ + my ($self,$sth) = @_; + + + if ($sth) { + $sth->finish(); + } +} + + +# Function to return the table prefix +sub table_prefix +{ + my $self = shift; + + return $self->{_table_prefix}; +} + + + + +1; +# vim: ts=4 diff --git a/smradius/dblayer.pm b/smradius/dblayer.pm new file mode 100644 index 00000000..efd910f7 --- /dev/null +++ b/smradius/dblayer.pm @@ -0,0 +1,292 @@ +# Common database layer module +# Copyright (C) 2005-2007 Nigel Kukard <nkukard@lbsd.net> +# Copyright (C) 2008, LinuxRulz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + + +package cbp::dblayer; + +use strict; +use warnings; + +# Exporter stuff +require Exporter; +our (@ISA,@EXPORT); +@ISA = qw(Exporter); +@EXPORT = qw( + DBConnect + DBSelect + DBDo + DBLastInsertID + DBBegin + DBCommit + DBRollback + DBQuote + DBFreeRes + + DBSelectNumResults + + hashifyLCtoMC +); + + + +use cbp::config; + +use cbp::dbilayer; + + +# Database handle +my $dbh = undef; + +# Our current error message +my $error = ""; + +# Set current error message +# Args: error_message +sub setError +{ + my $err = shift; + my ($package,$filename,$line) = caller; + my (undef,undef,undef,$subroutine) = caller(1); + + # Set error + $error = "$subroutine($line): $err"; +} + +# Return current error message +# Args: none +sub Error +{ + my $err = $error; + + # Reset error + $error = ""; + + # Return error + return $err; +} + + + +# Initialize database handle +# Args: <database handle> +sub setHandle +{ + my $handle = shift; + + $dbh = $handle; +} + + +# Return database selection results... +# Args: <select statement> +sub DBSelect +{ + my ($query,@params) = @_; + + + my $table_prefix = $dbh->table_prefix(); + + # Replace table prefix macro + $query =~ s/\@TP\@/$table_prefix/g; + + # Prepare query + my $sth; + if (!($sth = $dbh->select($query,@params))) { + setError("Error executing select '$query': ".$dbh->Error()); + return undef; + } + + return $sth; +} + + +# Perform a command +# Args: <command statement> +sub DBDo +{ + my ($command,@params) = @_; + + + my $table_prefix = $dbh->table_prefix(); + + # Replace table prefix macro + $command =~ s/\@TP\@/$table_prefix/g; + + # Prepare query + my $sth; + if (!($sth = $dbh->do($command,@params))) { + setError("Error executing command '$command': ".$dbh->Error()); + return undef; + } + + return $sth; +} + + +# Function to get last insert id +# Args: <table> <column> +sub DBLastInsertID +{ + my ($table,$column) = @_; + + + my $res; + if (!($res = $dbh->lastInsertID(undef,undef,$table,$column))) { + setError("Error getting last inserted id: ".$dbh->Error()); + return undef; + } + + return $res; +} + + +# Function to begin a transaction +# Args: none +sub DBBegin +{ + my $res; + if (!($res = $dbh->begin())) { + setError("Error beginning transaction: ".$dbh->Error()); + return undef; + } + + return $res; +} + + +# Function to commit a transaction +# Args: none +sub DBCommit +{ + my $res; + if (!($res = $dbh->commit())) { + setError("Error committing transaction: ".$dbh->Error()); + return undef; + } + + return $res; +} + + +# Function to rollback a transaction +# Args: none +sub DBRollback +{ + my $res; + if (!($res = $dbh->rollback())) { + setError("Error rolling back transaction: ".$dbh->Error()); + return undef; + } + + return $res; +} + + +# Function to quote a database variable +# Args: <stuff to quote> +sub DBQuote +{ + my $stuff = shift; + + + return $dbh->quote($stuff); +} + + +# Function to cleanup DB query +# Args: <sth> +sub DBFreeRes +{ + my $sth = shift; + + + if ($sth) { + $sth->finish(); + } +} + + + +# +# Value Added Functions +# + + +# Function to get table prefix +sub DBTablePrefix +{ + return $dbh->table_prefix(); +} + + + +# Return how many results came up from the specific SELECT query +# Args: <select statement> +sub DBSelectNumResults +{ + my $query = shift; + + + # Prepare query + my $sth; + if (!($sth = $dbh->select("SELECT COUNT(*) AS num_results $query"))) { + setError("Error executing select: ".$dbh->Error()); + return undef; + } + + # Grab row + my $row = $sth->fetchrow_hashref(); + if (!defined($row)) { + setError("Failed to get results from a select: ".$dbh->Error()); + return undef; + } + + # Pull number + my $num_results = $row->{'num_results'}; + $sth->finish(); + + return $num_results; +} + + +# Convert a lower case array to mixed case +sub hashifyLCtoMC +{ + my ($record,@entries) = @_; + + + # If we undefined, return + return undef if (!defined($record)); + + my $res; + + # Loop with each item, assign from lowecase database record to our result + foreach my $entry (@entries) { + $res->{$entry} = $record->{lc($entry)}; + } + + return $res; +} + + + + + +1; +# vim: ts=4 -- GitLab