initial commit

master
Ray Slakinski 2010-05-10 14:30:49 -04:00
commit d4f400855f
7 changed files with 302 additions and 0 deletions

5
.gitignore vendored 100644
View File

@ -0,0 +1,5 @@
.DS_Store
*.py[co]
*.pid
*.log
django_cache

28
LICENCE.txt 100644
View File

@ -0,0 +1,28 @@
Copyright (c) 2010, Ray Slakinski
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the author nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

38
README.markdown 100644
View File

@ -0,0 +1,38 @@
cassandra-sessions
==================
This is a session backend for Django that stores sessions in Cassandra
The advantage to using this over other solutions is that your data is persistent
unlike memcached, and Cassandra is designed to store key-value data like
this, so performance is much closer to that of memcached than with a database.
Installing cassandra-sessions
-----------------------------
1. Either download the tarball and run 'python setup.py install', or simply
use easy install or pip like so 'easy_install cassandra-sessions'.
2. Set 'cassandra-sessions' as your session engine, like so:
SESSION_ENGINE = 'cassandra-sessions'
3. Add settings describing where to connect to Cassandra:
CASSANDRA_POOL = ('127.0.0.1:9160',)
CASSANDRA_SESSION_KEYSPACE = 'Testing'
4. Create the Keyspace and Column Family in Cassandra:
<Keyspace Name="Testing">
<ColumnFamily Name="Sessions" CompareWith="UTF8Type"/>
<ReplicaPlacementStrategy>org.apache.cassandra.locator.RackUnawareStrategy</ReplicaPlacementStrategy>
<ReplicationFactor>1</ReplicationFactor>
<EndPointSnitch>org.apache.cassandra.locator.EndPointSnitch</EndPointSnitch>
</Keyspace>
That's it. Hopefully this backend gives you all the better performance while
still not sacrificing persistence.

View File

@ -0,0 +1,105 @@
import lazyboy
import time
import logging
from lazyboy.key import Key
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.encoding import force_unicode
from django.contrib.sessions.backends.base import SessionBase, CreateError
CASSANDRA_POOL = getattr(settings, 'CASSANDRA_POOL', None)
CASSANDRA_SESSION_KEYSPACE = getattr(settings, 'CASSANDRA_SESSION_KEYSPACE', None)
if CASSANDRA_POOL is None or CASSANDRA_SESSION_KEYSPACE is None:
raise ImproperlyConfigured(u'To use cassandra-sessions, you must first set the CASSANDRA_SESSION_KEYSPACE and CASSANDRA_POOL settings in your settings.py')
else:
try:
lazyboy.connection.get_pool(CASSANDRA_SESSION_KEYSPACE)
except lazyboy.exceptions.ErrorCassandraClientNotFound:
lazyboy.connection.add_pool(CASSANDRA_SESSION_KEYSPACE, CASSANDRA_POOL)
class SessionStore(SessionBase):
"""
A Cassandra-based session store.
"""
def get_session(self, session_key):
logging.debug('Getting session: %s' % session_key)
session = None
if session_key:
try:
key = Key(
keyspace=CASSANDRA_SESSION_KEYSPACE,
column_family="Sessions",
key=session_key
)
record = lazyboy.record.Record()
session_record = record.load(key)
session_values = session_record.values()
if session_values:
session = session_values[0]
except lazyboy.exceptions.ErrorNoSuchRecord:
pass
return session
def load(self):
session_data = self.get_session(self.session_key)
if session_data is not None:
expiry, data = int(session_data[:15]), session_data[15:]
if expiry < time.time():
return {}
else:
return self.decode(force_unicode(data))
self.create()
return {}
def create(self):
while True:
self.session_key = self._get_new_session_key()
try:
self.save()
except CreateError:
continue
self.modified = True
return
def save(self, must_create=True):
data = self.encode(self._get_session(no_load=True))
encoded = '%15d%s' % (int(time.time()) + self.get_expiry_age(), data)
key = Key(
keyspace=CASSANDRA_SESSION_KEYSPACE,
column_family="Sessions",
key=self.session_key
)
record = lazyboy.record.Record()
record.key = key
record[self.session_key] = encoded
record.save()
def exists(self, session_key):
session_data = self.get_session(session_key)
if session_data is not None:
expiry, data = int(session_data[:15]), session_data[15:]
if expiry < time.time():
return False
else:
return True
return False
def delete(self, session_key=None):
if session_key is None:
if self._session_key is None:
return
session_key = self._session_key
key = Key(
keyspace=CASSANDRA_SESSION_KEYSPACE,
column_family="Sessions",
key=session_key
)
# make this session expire right now
data = self.encode({})
encoded = '%15d%s' % (int(time.time()), data)
record = lazyboy.record.Record()
record.key = key
record[self.session_key] = encoded
record.save()

View File

@ -0,0 +1,13 @@
import lazyboy
import logging
logging.basicConfig(
level = logging.DEBUG,
format = '[%(asctime)s] %(levelname)s: "%(message)s"',
datefmt = '%d/%b/%Y %I:%M:%S'
)
CASSANDRA_POOL = ('127.0.0.1:9160',)
CASSANDRA_SESSION_KEYSPACE = 'Testing'
lazyboy.connection.add_pool(CASSANDRA_SESSION_KEYSPACE, CASSANDRA_POOL)

View File

@ -0,0 +1,46 @@
"""
>>> from django.conf import settings
>>> from cassandra_sessions import SessionStore as CassandraSession
>>> cassandra_session = CassandraSession()
>>> cassandra_session.modified
False
>>> cassandra_session.get('cat')
>>> cassandra_session['cat'] = "dog"
>>> cassandra_session.modified
True
>>> cassandra_session.pop('cat')
'dog'
>>> cassandra_session.pop('some key', 'does not exist')
'does not exist'
>>> cassandra_session.save()
>>> cassandra_session.exists(cassandra_session.session_key)
True
>>> cassandra_session.delete(cassandra_session.session_key)
>>> cassandra_session['foo'] = 'bar'
>>> cassandra_session.save()
>>> cassandra_session.exists(cassandra_session.session_key)
True
>>> prev_key = cassandra_session.session_key
>>> cassandra_session.flush()
>>> cassandra_session.exists(prev_key)
False
>>> cassandra_session.session_key == prev_key
False
>>> cassandra_session.modified, cassandra_session.accessed
(True, True)
>>> cassandra_session['a'], cassandra_session['b'] = 'c', 'd'
>>> cassandra_session.save()
>>> prev_key = cassandra_session.session_key
>>> prev_data = cassandra_session.items()
>>> cassandra_session.cycle_key()
>>> cassandra_session.session_key == prev_key
False
>>> cassandra_session.items() == prev_data
True
"""
if __name__ == '__main__':
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
import doctest
doctest.testmod()

67
setup.py 100644
View File

@ -0,0 +1,67 @@
from setuptools import setup, find_packages
version = '0.1.0'
LONG_DESCRIPTION = """
cassandra-sessions
==================
This is a session backend for Django that stores sessions in Cassandra
The advantage to using this over other solutions is that your data is persistent
unlike memcached, and Cassandra is designed to store key-value data like
this, so performance is much closer to that of memcached than with a database.
Installing cassandra-sessions
-----------------------------
1. Either download the tarball and run ``python setup.py install``, or simply
use easy install or pip like so ``easy_install cassandra-sessions``.
2. Set ``cassandra-sessions`` as your session engine, like so::
SESSION_ENGINE = 'cassandra-sessions'
3. Add settings describing where to connect to Cassandra::
CASSANDRA_POOL = ('127.0.0.1:9160',)
CASSANDRA_SESSION_KEYSPACE = 'Testing'
4. Create the Keyspace and Column Family in Cassandra::
<Keyspace Name="Testing">
<ColumnFamily Name="Sessions" CompareWith="UTF8Type"/>
<ReplicaPlacementStrategy>org.apache.cassandra.locator.RackUnawareStrategy</ReplicaPlacementStrategy>
<ReplicationFactor>1</ReplicationFactor>
<EndPointSnitch>org.apache.cassandra.locator.EndPointSnitch</EndPointSnitch>
</Keyspace>
That's it. Hopefully this backend gives you all the better performance while
still not sacrificing persistence.
"""
setup(
name='cassandra-sessions',
version=version,
description="This is a session backend for Django that stores sessions in Cassandra.",
long_description=LONG_DESCRIPTION,
classifiers=[
"Programming Language :: Python",
"Topic :: Software Development :: Libraries :: Python Modules",
"Framework :: Django",
"Environment :: Web Environment",
],
keywords='cassandra,session,lazyboy,django',
author='Ray Slakinski',
author_email='ray.slakinski@gmail.com',
url='http://github.com/rays/cassandra-sessions/tree/master',
license='BSD',
packages=find_packages(),
zip_safe=False,
install_requires=['setuptools'],
include_package_data=True,
setup_requires=['setuptools_git'],
)