Author: tziade
Date: Tue Oct  4 00:39:29 2005
New Revision: 27899

Added:
   z3lab/memramcached/
   z3lab/memramcached/__init__.py
   z3lab/memramcached/browser/
   z3lab/memramcached/browser/__init__.py   (contents, props changed)
   z3lab/memramcached/browser/configure.zcml   (contents, props changed)
   z3lab/memramcached/browser/memramcachedview.py
   z3lab/memramcached/browser/memramedit.pt   (contents, props changed)
   z3lab/memramcached/browser/memramstats.pt   (contents, props changed)
   z3lab/memramcached/configure.zcml
   z3lab/memramcached/interfaces/
   z3lab/memramcached/interfaces/__init__.py   (contents, props changed)
   z3lab/memramcached/interfaces/memramcached.py
   z3lab/memramcached/memramcached.py
   z3lab/memramcached/memramcaching.py
   z3lab/memramcached/tests/
   z3lab/memramcached/tests/__init__.py
   z3lab/memramcached/tests/test_memramcached.py
Log:
initial commit of a tentative ramcache based on memcached server

Added: z3lab/memramcached/__init__.py
==============================================================================
--- (empty file)
+++ z3lab/memramcached/__init__.py      Tue Oct  4 00:39:29 2005
@@ -0,0 +1 @@
+#
\ No newline at end of file

Added: z3lab/memramcached/browser/__init__.py
==============================================================================
--- (empty file)
+++ z3lab/memramcached/browser/__init__.py      Tue Oct  4 00:39:29 2005
@@ -0,0 +1 @@
+#
\ No newline at end of file

Added: z3lab/memramcached/browser/configure.zcml
==============================================================================
--- (empty file)
+++ z3lab/memramcached/browser/configure.zcml   Tue Oct  4 00:39:29 2005
@@ -0,0 +1,30 @@
+<zope:configure
+   xmlns:zope="http://namespaces.zope.org/zope";
+   xmlns="http://namespaces.zope.org/browser";
+   >
+
+  <tool
+      interface="memramcached.interfaces.memramcached.IMemRAMCached"
+      title="memcached Caches"
+      description="Caches linking to memcached server(s)"
+      />
+
+  <addMenuItem
+      title="memcached RAM Cache"
+      description="A RAM cache linking to a memcached server"
+      class="memramcached.memramcached.MemRAMCached"
+      permission="zope.ManageServices"
+      />
+
+  <pages
+      for="memramcached.interfaces.memramcached.IMemRAMCached"
+      class=".memramcachedview.MemRAMCachedView"
+      permission="zope.ManageServices">
+    <page name="editAction.html" attribute="action" />
+    <page name="index.html" template="memramedit.pt"
+          menu="zmi_views" title="Edit"/>
+    <page name="stats.html" template="memramstats.pt"
+          menu="zmi_views" title="Statistics"/>
+  </pages>
+
+</zope:configure>

Added: z3lab/memramcached/browser/memramcachedview.py
==============================================================================
--- (empty file)
+++ z3lab/memramcached/browser/memramcachedview.py      Tue Oct  4 00:39:29 2005
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+# -*- coding: ISO-8859-15 -*-
+# (C) Copyright 2005 Nuxeo SARL <http://nuxeo.com>
+# Author: Tarek Ziad� <[EMAIL PROTECTED]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+# $Id:$
+__docformat__ = 'restructuredtext'
+
+from zope.app.publisher.browser import BrowserView
+from memramcached.interfaces.memramcached import IMemRAMCached
+
+class MemRAMCachedView(BrowserView):
+
+    __used_for__ = IMemRAMCached
+
+    def action(self, maxEntries=None, maxAge=None, cleanupInterval=None,
+               memcachedHost='127.0.0.1', memcachedPort=11211):
+        self.context.update(maxEntries, maxAge, cleanupInterval,
+                            memcachedHost, memcachedPort)
+        self.request.response.redirect('.')

Added: z3lab/memramcached/browser/memramedit.pt
==============================================================================
--- (empty file)
+++ z3lab/memramcached/browser/memramedit.pt    Tue Oct  4 00:39:29 2005
@@ -0,0 +1,80 @@
+<html metal:use-macro="context/@@standard_macros/view">
+<body>
+<div metal:fill-slot="body">
+
+  <p i18n:translate="">You can configure the memcached RAM Cache here.</p>
+
+  <div tal:condition="python: options.has_key('errors') and
+                              options['errors']">
+    <span style="font-weight: bold" i18n:translate="">Errors</span>:
+    <div tal:repeat="error options/errors | nothing">
+      <span tal:replace="python: error[0].title" />:
+      <span tal:replace="python: error[1].error_name" />
+    </div>
+  </div>
+  <br />
+
+  <form action="./" method="post" enctype="multipart/form-data">
+    <table class="EditTable">
+      <tr>
+        <th class="EditAttributeName" i18n:translate="">
+          Maximum cached entries
+        </th>
+        <td class="EditAttributeValue">
+          <input type="text" name="maxEntries:int"
+                 tal:attributes="value context/maxEntries"/>
+
+        </td>
+      </tr>
+      <tr>
+        <th class="EditAttributeName" i18n:translate="">
+          Maximum age of cached entries
+        </th>
+        <td class="EditAttributeValue">
+          <input type="text" name="maxAge:int"
+                 tal:attributes="value context/maxAge"/>
+
+        </td>
+      </tr>
+      <tr>
+        <th class="EditAttributeName" i18n:translate="">
+          Time between cache cleanups
+        </th>
+        <td class="EditAttributeValue">
+          <input type="text" name="cleanupInterval:int"
+                 tal:attributes="value context/cleanupInterval"/>
+
+        </td>
+      </tr>
+      <tr>
+        <th class="EditAttributeName" i18n:translate="">
+          memcached server
+        </th>
+        <td class="EditAttributeValue">
+          <input type="text" name="memcachedHost:str"
+                 tal:attributes="value context/memcachedHost"/>
+
+        </td>
+      </tr>
+      <tr>
+        <th class="EditAttributeName" i18n:translate="">
+          memcached port
+        </th>
+        <td class="EditAttributeValue">
+          <input type="text" name="memcachedPort:int"
+                 tal:attributes="value context/memcachedPort"/>
+
+        </td>
+      </tr>
+    </table>
+
+    <input type="submit" name="editAction.html:method" value="Save Changes"
+           i18n:attributes="value save-changes-button" />
+    <input type="reset" value="Reset" i18n:attributes="value reset-button" />
+  </form>
+  <div tal:content="options/message|nothing" i18n:translate=""/>
+
+</div>
+</body>
+
+</html>

Added: z3lab/memramcached/browser/memramstats.pt
==============================================================================
--- (empty file)
+++ z3lab/memramcached/browser/memramstats.pt   Tue Oct  4 00:39:29 2005
@@ -0,0 +1,41 @@
+<html metal:use-macro="context/@@standard_macros/view">
+<body>
+<div metal:fill-slot="body">
+
+  <p><span tal:replace="context/zope:name"/>
+    <span i18n:translate="">MemRAMCached statistics</span></p>
+
+  <div tal:condition="python: options.has_key('errors') and
+                              options['errors']">
+    <span style="font-weight: bold" i18n:translate="">Errors</span>:
+    <div tal:repeat="error options/errors | nothing">
+      <span tal:replace="python: error[0].title" />:
+      <span tal:replace="python: error[1].error_name" />
+    </div>
+  </div>
+  <br />
+  <table  id="sortable" class="listing" summary="Content listing"
+         cellpadding="2" cellspacing="0" >
+    <thead>
+      <th i18n:translate="">Path</th>
+      <th i18n:translate="">Hits</th>
+      <th i18n:translate="">Misses</th>
+      <th i18n:translate="">Size, bytes</th>
+      <th i18n:translate="">Entries</th>
+    </thead>
+    <tbody>
+      <tr tal:repeat="data context/getStatistics">
+        <td><span tal:content="data/path">&nbsp;</span></td>
+        <td><span tal:content="data/hits">&nbsp;</span></td>
+        <td><span tal:content="data/misses">&nbsp;</span></td>
+        <td><span tal:content="data/size">&nbsp;</span></td>
+        <td><span tal:content="data/entries">&nbsp;</span></td>
+      </tr>
+    </tbody>
+  </table>
+
+  <div tal:content="options/message|nothing" i18n:translate=""/>
+</div>
+</body>
+
+</html>

Added: z3lab/memramcached/configure.zcml
==============================================================================
--- (empty file)
+++ z3lab/memramcached/configure.zcml   Tue Oct  4 00:39:29 2005
@@ -0,0 +1,33 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope";
+    i18n_domain="zope">
+
+
+  <content class=".memramcached.MemRAMCached">
+    <factory
+        id="memramcached.memramcached.MemRAMCached"
+        />
+
+    <implements
+        interface=".interfaces.memramcached.IMemRAMCached"
+        />
+
+    <implements
+        interface="zope.app.annotation.interfaces.IAttributeAnnotatable"
+        />
+
+    <implements
+        interface="zope.app.utility.interfaces.ILocalUtility"
+        />
+
+    <require
+        permission="zope.ManageServices"
+        interface=".interfaces.memramcached.IMemRAMCached"
+        />
+  </content>
+
+  <!-- Include browser package -->
+
+  <include package=".browser" />
+
+</configure>

Added: z3lab/memramcached/interfaces/__init__.py
==============================================================================
--- (empty file)
+++ z3lab/memramcached/interfaces/__init__.py   Tue Oct  4 00:39:29 2005
@@ -0,0 +1,62 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Interfaces for cache manager.
+
+$Id: __init__.py 27409 2004-09-02 07:05:38Z pruggera $
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.interface import Interface
+from zope.schema import Choice
+
+class ICacheable(Interface):
+    """Object that can be associated with a cache manager."""
+
+    cacheId = Choice(
+        title=u"Cache Name",
+        description=u"The name of the cache used for this object.",
+        required=True,
+        vocabulary="Cache Names")
+
+    def getCacheId():
+        """Gets the associated cache manager ID."""
+
+    def setCacheId(id):
+        """Sets the associated cache manager ID."""
+
+
+class ICache(Interface):
+    """Interface for caches."""
+
+    def invalidate(ob, key=None):
+        """Invalidates cached entries that apply to the given object.
+
+        `ob` is an object location.  If `key` is specified, only
+        invalidates entry for the given key.  Otherwise invalidates
+        all entries for the object.
+        """
+
+    def invalidateAll():
+        """Invalidates all cached entries."""
+
+    def query(ob, key=None, default=None):
+        """Returns the cached data previously stored by `set()`.
+
+        `ob` is the location of the content object being cached.  `key` is
+        a mapping of keywords and values which should all be used to
+        select a cache entry.
+        """
+
+    def set(data, ob, key=None):
+        """Stores the result of executing an operation."""

Added: z3lab/memramcached/interfaces/memramcached.py
==============================================================================
--- (empty file)
+++ z3lab/memramcached/interfaces/memramcached.py       Tue Oct  4 00:39:29 2005
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+# -*- coding: ISO-8859-15 -*-
+# (C) Copyright 2005 Nuxeo SARL <http://nuxeo.com>
+# Author: Tarek Ziad� <[EMAIL PROTECTED]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+# $Id:$
+__docformat__ = 'restructuredtext'
+
+from zope.app.cache.interfaces.ram import IRAMCache
+from zope.interface import Attribute
+
+class IMemRAMCached(IRAMCache):
+    """Interface for the memcached RAM Cache."""
+    memcachedHost = Attribute("""memcached Host""")
+    memcachedPort = Attribute("""memcached Port""")
+
+    def update(maxEntries, maxAge, cleanupInterval, memcachedHost,
+               memcachedPort):
+        """ xxx """

Added: z3lab/memramcached/memramcached.py
==============================================================================
--- (empty file)
+++ z3lab/memramcached/memramcached.py  Tue Oct  4 00:39:29 2005
@@ -0,0 +1,137 @@
+#!/usr/bin/python
+# -*- coding: ISO-8859-15 -*-
+# (C) Copyright 2005 Nuxeo SARL <http://nuxeo.com>
+# Author: Tarek Ziad� <[EMAIL PROTECTED]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+# $Id:$
+__docformat__ = 'restructuredtext'
+""" doc here
+"""
+
+import atexit
+from thread import allocate_lock
+
+from persistent import Persistent
+
+from zope.interface import implements
+from zope.app import zapi
+from zope.app.container.contained import Contained
+
+from interfaces.memramcached import IMemRAMCached
+
+import memcache
+
+# keep a global pool of all connectors
+_connectors = {}
+
+locker = allocate_lock()
+
+# called on zope exit, to cleanly disconnect all
+# connectors
+def disconnectConnectors():
+    for connector in _connectors:
+        _connectors[connector].disconnect_all()
+atexit.register(disconnectConnectors)
+
+class MemRAMCached(Persistent, Contained):
+    """ memcached RAM Cache """
+    implements(IMemRAMCached)
+
+    def __init__(self):
+        self.maxEntries = 1000
+        self.maxAge = 3600
+        self.cleanupInterval = 300
+        self.memcachedHost = '127.0.0.1'
+        self.memcachedPort = 11211
+
+    def _getConnector(self):
+        """ return a link to memcached server """
+        link = '%s:%d' % (self.memcachedHost, self.memcachedPort)
+        global _connectors
+
+        # add it to the global pool if not already in there
+        locker.acquire()
+        try:
+            if not link in _connectors:
+                connector = memcache.Client([link], debug=0)
+                _connectors[link] = connector
+        finally:
+            locker.release()
+
+        return _connectors[link]
+
+    def _calculateKey(self, ob, key):
+        """ returns a key
+
+        XXX need to cache this
+        """
+        if isinstance(key, dict):
+            key = tuple(key.items())
+
+        if ob is not None:
+            # XXX see if id() is ok
+            return id(ob), key
+        else:
+            return key
+
+    def getStatistics(self):
+        """ see IRamCache """
+        return None
+
+    def update(self,  maxEntries=None, maxAge=None, cleanupInterval=None,
+               memcachedHost = '127.0.0.1', memcachedPort = 11211):
+        """ see ICache """
+        if maxEntries is not None:
+            self.maxEntries = maxEntries
+
+        if maxAge is not None:
+            self.maxAge = maxAge
+
+        if cleanupInterval is not None:
+            self.cleanupInterval = cleanupInterval
+
+        if memcachedHost is not None:
+            self.memcachedHost = memcachedHost
+
+        if memcachedPort is not None:
+            self.memcachedPort = memcachedPort
+
+    def invalidate(self, ob, key=None):
+        """ see ICache """
+        key = self._calculateKey(ob, key)
+        connector = self._getConnector()
+        connector.delete(key)
+
+    def invalidateAll(self):
+        """ see ICache """
+        raise NotImplementedError
+
+    def query(self, ob, key=None, default=None):
+        """ see IRAMCache """
+        key = self._calculateKey(ob, key)
+        connector = self._getConnector()
+        result = connector.get(key)
+        if result is None:
+            return default
+        else:
+            return result
+
+    def set(self, data, ob, key=None):
+        """ see IRAMCache """
+        key = self._calculateKey(ob, key)
+        connector = self._getConnector()
+        connector.set(key, data)

Added: z3lab/memramcached/memramcaching.py
==============================================================================
--- (empty file)
+++ z3lab/memramcached/memramcaching.py Tue Oct  4 00:39:29 2005
@@ -0,0 +1,45 @@
+#!/usr/bin/python
+# -*- coding: ISO-8859-15 -*-
+# (C) Copyright 2005 Nuxeo SARL <http://nuxeo.com>
+# Author: Tarek Ziad� <[EMAIL PROTECTED]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+# $Id:$
+
+"""Helpers for caching.
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.app import zapi
+from zope.app.cache.interfaces import ICacheable, ICache
+from zope.component import ComponentLookupError
+
+def getCacheForObject(obj):
+    """Returns the cache associated with `obj` or ``None``."""
+    adapter = ICacheable(obj, None)
+    if adapter is None:
+        return None
+    cache_id = adapter.getCacheId()
+    if not cache_id:
+        return None
+    return zapi.getUtility(ICache, cache_id)
+
+def getLocationForCache(obj):
+    """Returns the location to be used for caching the object or ``None``."""
+    try:
+        return zapi.getPath(obj)
+    except (ComponentLookupError, TypeError):
+        return None

Added: z3lab/memramcached/tests/__init__.py
==============================================================================
--- (empty file)
+++ z3lab/memramcached/tests/__init__.py        Tue Oct  4 00:39:29 2005
@@ -0,0 +1 @@
+#
\ No newline at end of file

Added: z3lab/memramcached/tests/test_memramcached.py
==============================================================================
--- (empty file)
+++ z3lab/memramcached/tests/test_memramcached.py       Tue Oct  4 00:39:29 2005
@@ -0,0 +1,98 @@
+#!/usr/bin/python
+# -*- coding: ISO-8859-15 -*-
+# (C) Copyright 2005 Nuxeo SARL <http://nuxeo.com>
+# Author: Tarek Ziad� <[EMAIL PROTECTED]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+# $Id:$
+
+from time import time
+from unittest import TestCase, TestSuite, main, makeSuite
+
+from zope.interface.verify import verifyClass, verifyObject
+from zope.interface import implements
+
+from zope.app.cache.tests.test_icache import BaseICacheTest
+from zope.app.cache.interfaces import ICache
+from zope.app.cache.interfaces.ram import IRAMCache
+from zope.app.traversing.interfaces import IPhysicallyLocatable
+from zope.app.tests.placelesssetup import PlacelessSetup
+
+from memramcached.memramcached import MemRAMCached
+
+class Locatable(object):
+
+    __name__ = __parent__ = None
+
+    implements(IPhysicallyLocatable)
+
+    def __init__(self, path=('a', 'b')):
+        self.path = path
+
+    def getRoot(self):
+        return self
+
+    def getPath(self):
+        return self.path
+
+class FakeConnector(object):
+
+    def __init__(self):
+        self._datas = {}
+
+    def set(self, key, ob):
+        self._datas[key] = ob
+
+    def get(self, key):
+        if key in self._datas:
+            return self._datas[key]
+        else:
+            return None
+
+    def delete(self, key):
+        # we suppose memcache won't raise an error if the key does not exists
+        if key in self._datas:
+            del self._datas[key]
+
+connector = FakeConnector()
+
+class TestMemRAMCache(PlacelessSetup, TestCase, BaseICacheTest):
+
+    __name__ = __parent__ = None
+
+    def _getConnector(self):
+        return connector
+
+    def _Test__new(self):
+        ob = MemRAMCached()
+        ob._getConnector = self._getConnector
+        return ob
+
+    def test_interface(self):
+        verifyObject(IRAMCache, MemRAMCached())
+        verifyClass(ICache, MemRAMCached)
+
+    def testInvalidateAll(self):
+        pass
+
+class Test(TestCase):
+    pass
+
+def test_suite():
+    return TestSuite((makeSuite(TestMemRAMCache),))
+
+if __name__=='__main__':
+    main(defaultTest='test_suite')
-- 
http://lists.nuxeo.com/mailman/listinfo/z3lab-checkins

Reply via email to