Browse Source

Implemented new DB modules with unit test

master
Artyom Beilis 12 years ago
parent
commit
09fee5b840
10 changed files with 310 additions and 34 deletions
  1. +8
    -0
      contrib/server_side/sessions/CMakeLists.txt
  2. +8
    -0
      contrib/server_side/sessions/berkeley_db/CMakeLists.txt
  3. +6
    -12
      contrib/server_side/sessions/berkeley_db/bdb.cpp
  4. +25
    -0
      contrib/server_side/sessions/cleanup.sh
  5. +8
    -0
      contrib/server_side/sessions/cppdb/CMakeLists.txt
  6. +22
    -21
      contrib/server_side/sessions/cppdb/cppdb_storage.cpp
  7. +7
    -0
      contrib/server_side/sessions/sqlite3/CMakeLists.txt
  8. +1
    -1
      contrib/server_side/sessions/sqlite3/session_sqlite_storage.cpp
  9. +162
    -0
      contrib/server_side/sessions/storage_test.cpp
  10. +63
    -0
      contrib/server_side/sessions/tests.js

+ 8
- 0
contrib/server_side/sessions/CMakeLists.txt View File

@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 2.6)

add_subdirectory(sqlite3)
add_subdirectory(cppdb)
add_subdirectory(berkeley_db)

add_executable(tester storage_test.cpp)
target_link_libraries(tester cppcms booster)

+ 8
- 0
contrib/server_side/sessions/berkeley_db/CMakeLists.txt View File

@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 2.6)

if(WIN32 OR CYGWIN)
add_definitions(-DDLL_EXPORT)
endif()

add_library(cppcms_session_bdb SHARED bdb.cpp)
target_link_libraries(cppcms_session_bdb cppcms booster db)

+ 6
- 12
contrib/server_side/sessions/berkeley_db/bdb.cpp View File

@@ -16,6 +16,8 @@



namespace { // anon

extern "C" {
static int get_key(DB *, const DBT *, const DBT *pdata, DBT *skey)
{
@@ -159,7 +161,7 @@ private:
uint64_t val = val_in;
union { char c[8]; int64_t v; } u;
for(unsigned i=0;i<8;i++) {
u.c[i]=val >> 46;
u.c[i]=val >> 56;
val <<=8;
}
return u.v;
@@ -208,9 +210,6 @@ private:
booster::thread_specific_ptr<single_storage> ptr_;
};

///
/// \brief The factory is an interface to a factory that creates session_storage objects, it should be thread safe.
///
class bdb_factory : public cppcms::sessions::session_storage_factory {
public:
virtual booster::shared_ptr<cppcms::sessions::session_storage> get()
@@ -218,17 +217,10 @@ public:
return storage_;
}

///
/// Return true if session_storage requires garbage collection - removal of expired session time-to-time
///
virtual bool requires_gc()
{
return false;
}
///
/// Actual garbage collection job (if required). If requires_gc returns true it will be called once-in-a-while to remove
/// all expired objects from the DB.
///
virtual void gc_job()
{

@@ -248,8 +240,10 @@ private:
# define STORAGE_API
#endif

} // namespace

extern "C" {
STORAGE_API cppcms::sessions::session_storage_factory *session_factory(cppcms::json::value const &v)
STORAGE_API cppcms::sessions::session_storage_factory *sessions_generator(cppcms::json::value const &v)
{
std::string dir = v.get<std::string>("directory");
return new bdb_factory(dir);


+ 25
- 0
contrib/server_side/sessions/cleanup.sh View File

@@ -0,0 +1,25 @@
#!/bin/bash

cleanall()
{
pushd $1
rm -fr CMakeCache.txt CMakeFiles cmake_install.cmake Makefile
popd
}

cleanall .
cleanall berkeley_db
cleanall cppdb
cleanall sqlite3

rm -f *.db
rm -fr db/*

mysql -u root --password=root test <<EOF
drop table cppdb_sessions;
EOF

psql test <<EOF
drop table cppdb_sessions;
EOF


+ 8
- 0
contrib/server_side/sessions/cppdb/CMakeLists.txt View File

@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 2.6)

if(WIN32 OR CYGWIN)
add_definitions(-DDLL_EXPORT)
endif()

add_library(cppcms_session_cppdb SHARED cppdb_storage.cpp)
target_link_libraries(cppcms_session_cppdb cppcms booster cppdb)

+ 22
- 21
contrib/server_side/sessions/cppdb/cppdb_storage.cpp View File

@@ -41,7 +41,7 @@ public:
switch(transaction_mode_) {
case relaxed:
case non_durable:
sql << "SET SESSION synchronous_commit OFF" << cppdb::exec;
sql << "SET SESSION synchronous_commit = OFF" << cppdb::exec;
break;
default:
;
@@ -112,10 +112,10 @@ public:
{
cppdb::session sql(conn_str_);
set_session_option(sql);
sql << "DELETE FROM sessions "
sql << "DELETE FROM cppdb_sessions "
"WHERE sid in "
"("
" SELECT sid FROM sessions "
" SELECT sid FROM cppdb_sessions "
" WHERE timeout < ?"
")" << cppdb::exec;
}
@@ -150,13 +150,13 @@ public:
switch(engine_) {
case sqlite3:
{
sql << "CREATE TABLE IF NOT EXISTS sessions ("
" id varchar(32) primary key not null, "
sql << "CREATE TABLE IF NOT EXISTS cppdb_sessions ("
" sid varchar(32) primary key not null, "
" timeout bigint not null, "
" content blob non null "
" content blob not null "
")" << cppdb::exec;
sql << "CREATE INDEX IF NOT EXISTS "
"sessions_timeout on sessions(timeout)" << cppdb::exec;
"sessions_timeout on cppdb_sessions(timeout)" << cppdb::exec;
std::string ver;
sql << "SELECT sqlite_version()" << cppdb::row >> ver;
size_t pos = ver.find('.');
@@ -183,39 +183,40 @@ public:
{
switch(transaction_mode_) {
case acid:
sql << "CREATE TABLE IF NOT EXISTS sessions ("
" id varchar(32) primary key not null, "
sql << "CREATE TABLE IF NOT EXISTS cppdb_sessions ("
" sid varchar(32) primary key not null, "
" timeout bigint not null, "
" content blob non null "
" content blob not null, "
" index sessions_timeout (timeout) "
") Engine=InnoDB" << cppdb::exec;
break;
case relaxed:
case non_durable:
sql << "CREATE TABLE IF NOT EXISTS sessions ("
" id varchar(32) primary key not null, "
sql << "CREATE TABLE IF NOT EXISTS cppdb_sessions ("
" sid varchar(32) primary key not null, "
" timeout bigint not null, "
" content blob non null "
" content blob not null, "
" index sessions_timeout (timeout) "
") Engine=MyISAM" << cppdb::exec;
break;
}
sql << "CREATE INDEX IF NOT EXISTS "
"sessions_timeout on sessions(timeout)" << cppdb::exec;
}
break;
case postgresql:
{
cppdb::transaction tr(sql);
cppdb::result r = sql
<< "SELECT 1 FROM pg_tables "
"WHERE tablename = 'sessions' "
"WHERE tablename = 'cppdb_sessions' "
<<cppdb::row;
if(r.empty()) {
sql << "CREATE TABLE sessions ("
" id varchar(32) primary key not null, "
sql << "CREATE TABLE cppdb_sessions ("
" sid varchar(32) primary key not null, "
" timeout bigint not null, "
" content bytea non null "
" content bytea not null "
")" << cppdb::exec;
sql << "CREATE INDEX IF NOT EXISTS "
"sessions_timeout on sessions(timeout)" << cppdb::exec;
sql << "CREATE INDEX "
"sessions_timeout on cppdb_sessions(timeout)" << cppdb::exec;
}
tr.commit();
}


+ 7
- 0
contrib/server_side/sessions/sqlite3/CMakeLists.txt View File

@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 2.6)
if(WIN32 OR CYGWIN)
add_definitions(-DDLL_EXPORT)
endif()

add_library(cppcms_session_sqlite3 SHARED session_sqlite_storage.cpp)
target_link_libraries(cppcms_session_sqlite3 cppcms booster sqlite3)

+ 1
- 1
contrib/server_side/sessions/sqlite3/session_sqlite_storage.cpp View File

@@ -370,7 +370,7 @@ private:
#endif

extern "C" {
STORAGE_API cppcms::sessions::session_storage_factory *session_generator(cppcms::json::value const &opt)
STORAGE_API cppcms::sessions::session_storage_factory *sessions_generator(cppcms::json::value const &opt)
{
return new factory_object(opt.get<std::string>("db"));
}


+ 162
- 0
contrib/server_side/sessions/storage_test.cpp View File

@@ -0,0 +1,162 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#include <cppcms/defs.h>
#include <stdexcept>
#include <sstream>
#include <cppcms/session_storage.h>
#include <cppcms/json.h>
#include <booster/function.h>
#include <booster/shared_object.h>
#include <booster/backtrace.h>
#include <string.h>
#include <memory>
#include <iostream>
#include <vector>
#include <stdio.h>
#include <time.h>


#define TEST(X) \
do { \
if(X) break; \
std::cerr << "Error " << __FILE__ << ":"<<__LINE__ << " "#X << std::endl; \
std::ostringstream oss; \
oss << "Error " << __FILE__ << ":"<<__LINE__ << " "#X; \
throw std::runtime_error(oss.str()); \
}while(0)

std::string bs="0123456789abcdef0123456789abcde";

void do_nothing() {}


void test(booster::shared_ptr<cppcms::sessions::session_storage> storage,booster::function<void()> callback=do_nothing)
{
time_t now=time(0)+3;
callback();
storage->save(bs+"1",now,"");
std::string out="xx";
time_t tout;
callback();
TEST(storage->load(bs+"1",tout,out));
TEST(out.empty());
TEST(tout==now);
callback();
storage->remove(bs+"1");
callback();
TEST(!storage->load(bs+"1",tout,out));
callback();
storage->save(bs+"1",now-4,"hello world");
callback();
TEST(!storage->load(bs+"1",tout,out));
callback();
storage->save(bs+"1",now,"hello world");
callback();
TEST(storage->load(bs+"1",tout,out));
callback();
TEST(out=="hello world");
storage->save(bs+"2",now,"x");
callback();
storage->remove(bs+"2");
callback();
TEST(storage->load(bs+"1",tout,out));
TEST(out=="hello world");
callback();
storage->remove(bs+"1");
callback();
storage->remove(bs+"2");
callback();
}


struct do_gc {
cppcms::sessions::session_storage_factory *f;
int n;
void operator()() const
{
for(int i=0;i<n;i++) {
f->gc_job();
}
}
};

int main()
{
bool failed = false;
try {
cppcms::json::value v;
std::cin >> v;

if(!std::cin) {
std::cerr<< "Parsing failed" << std::endl;
return 1;
}

cppcms::json::array &all=v.array();


for(size_t i=0;i<all.size() && !failed;i++) {
std::string so = v[i].get<std::string>("so");
std::string clean = v[i].get("clean","");
if(!clean.empty()) {
system(clean.c_str());
}
std::cout << "- Module: " << so << std::endl << v[i].get("test","") << std::endl;
booster::shared_object obj(so);
{
booster::shared_ptr<cppcms::sessions::session_storage> storage;
std::auto_ptr<cppcms::sessions::session_storage_factory> storage_factory;
cppcms::sessions::cppcms_session_storage_generator_type gen;
obj.symbol(gen,"sessions_generator");
try {
storage_factory.reset(gen(v[i]));
storage = storage_factory->get();
std::cout << "-- Without gc" << std::endl;
test(storage);
std::cout << "-- With gc" << std::endl;
do_gc gc = { storage_factory.get() };
test(storage,gc);
std::cout << "-- Complete" << std::endl;
}
catch(std::exception const &e) {
std::cerr << e.what() << std::endl;
std::cerr << booster::trace(e) << std::endl;
storage.reset();
storage_factory.reset();
obj.close();
break;
}
storage.reset();
storage_factory.reset();
}
obj.close();
}

}
catch(std::exception const &e) {
std::cerr <<"Fail: " << e.what() << std::endl;
std::cerr << booster::trace(e) << std::endl;
return 1;
}
if(failed)
std::cerr << "Fail" << std::endl;
else
std::cout << "Ok" << std::endl;
return 0;
}

+ 63
- 0
contrib/server_side/sessions/tests.js View File

@@ -0,0 +1,63 @@
[
{
"so" : "./sqlite3/libcppcms_session_sqlite3.so",
"test" : "Sqlite3 native",
"db" : "cppdb.db",
"clean" : "rm cppdb.db",
},
{
"so" : "./berkeley_db/libcppcms_session_bdb.so",
"test" : "Berkeley DB",
"directory" : "./db/",
"clean" : "rm -f ./db/*"
},
{
"so" : "./cppdb/libcppcms_session_cppdb.so",
"test" : "sqlite3 acid",
"connection_string" : "sqlite3:db=cppdb.db",
"clean" : "rm cppdb.db",
"transactivity" : "acid"
},
{
"so" : "./cppdb/libcppcms_session_cppdb.so",
"test" : "sqlite3 relaxed ",
"connection_string" : "sqlite3:db=cppdb.db",
"clean" : "rm cppdb.db",
"transactivity" : "relaxed"
},
{
"so" : "./cppdb/libcppcms_session_cppdb.so",
"test" : "sqlite3 non_durable ",
"connection_string" : "sqlite3:db=cppdb.db",
"clean" : "rm cppdb.db",
"transactivity" : "non_durable"
},
{
"so" : "./cppdb/libcppcms_session_cppdb.so",
"test" : "mysql acid",
"connection_string" : "mysql:database=test;user=root;password=root;host=localhost",
"clean" : "mysql -u root --password=root test -e 'drop table cppdb_sessions;'",
"transactivity" : "acid"
},
{
"so" : "./cppdb/libcppcms_session_cppdb.so",
"test" : "mysql relaxed",
"connection_string" : "mysql:database=test;user=root;password=root;host=localhost",
"clean" : "mysql -u root --password=root test -e 'drop table cppdb_sessions;'",
"transactivity" : "relaxed"
},
{
"so" : "./cppdb/libcppcms_session_cppdb.so",
"test" : "postgresql acid",
"connection_string" : "postgresql:dbname=test;@blob=bytea",
"clean" : "psql test -c 'drop table cppdb_sessions;'",
"transactivity" : "acid"
},
{
"so" : "./cppdb/libcppcms_session_cppdb.so",
"test" : "postgresql relaxed",
"connection_string" : "postgresql:dbname=test;@blob=bytea",
"clean" : "psql test -c 'drop table cppdb_sessions;'",
"transactivity" : "relaxed"
},
]

Loading…
Cancel
Save