memcacheについて昨日の記事の訂正

昨日の記事で書いたmemcacheに関する内容に2点間違いがありましたので訂正です。

1つ目はmemcacheにはリストを保存できないと書いたことです。memcacheにはリストを保存できないのでJSON化した上で文字列として保存していると書いたのですが実際はリストや辞書も保存できます。

2つ目はGAEのMemcache Viewerの

・Cache contains items up to 17 minutes old.

という項目についてです。昨日の記事ではこの項目について

「前回キャッシュが完全にクリアされてからの時間」を表しており、現在保存されているデータの有無とは関係がありません。
Memcache Viewer内にあるFlush Cacheボタンを押されてからの時間、またはサーバが起動されてからの時間ということになります。

と書いたのですがこれは正しくありませんでした。
memcacheの保存内容はキャッシュの容量がいっぱいになると押し出されるように古い方から消去されますが、この項目で表示される時間(上の例では17分)に保存されたデータは「押し出される形では」消えていないということを表しているようです。
つまり容量がいっぱいにならない限りは「Flush Cacheボタンを押されてからの時間、またはサーバが起動されてからの時間」と等しくなりますが、容量オーバーによる押し出しが発生した場合は「直近に押し出されたデータが保存された時からの経過時間」ということになります。
そのため次に押し出されるデータはこの時間内に保存されたデータのうち最も古いものになります。

以上を踏まえ昨日のコードを書きなおしたものが以下です。
memcaheの修正以外に昨日のコードではPython標準のcgiモジュールを使用して行なっていたHTMLタグのエスケープ処理をJinja2のオートエスケープを使って行うようにしました。

# coding: utf-8

import webapp2
import os
import binascii
import jinja2
from google.appengine.api import memcache

jinja_environment = jinja2.Environment(
    autoescape=True,
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))

DEFAULTUSER = {'name': 'GUEST', 'words': []}


class MainPage(webapp2.RequestHandler):
    def _screenwrite(self, session_cookie=False, user=DEFAULTUSER):
        """
        HTMLを出力する。
        session_cookie:新たにcookieを発行する場合のID
        user:mamcacheから取得した該当user
        """
        self.response.headers['Content-Type'] = 'text/html;charset=utf-8'

        if session_cookie:
            self.response.set_cookie('sessionID', session_cookie, max_age=300)

        template = jinja_environment.get_template('sessiontest.html')
        self.response.out.write(template.render(user=user))

    def get(self):
        sessionID = self.request.cookies.get('sessionID')

        if sessionID and memcache.get(sessionID):
            # すでにセッションがある場合はpostの場合を実行
            self.post()
            return

        #新しくIDを作成
        sessionID = binascii.hexlify(os.urandom(8))

        memcache.set(key=sessionID, value=DEFAULTUSER, time=330)

        self._screenwrite(session_cookie=sessionID)

    def post(self):
        sessionID = self.request.cookies.get('sessionID')

        if not (sessionID and memcache.get(sessionID)):
            #sessionIDが未設定、もしくはmemcacheにない場合はget()を実行
            self.get()
            return

        #該当するセッションを取得
        session = memcache.get(sessionID)

        session['name'] = self.request.get('username') or session['name']
        if self.request.get('word'):
            session['words'].append(self.request.get('word'))

        memcache.replace(key=sessionID, value=session, time=330)

        self._screenwrite(user=session)

app = webapp2.WSGIApplication([('/', MainPage)],
                              debug=True)