text: 
  /*
   * Copyright (C) Xiaozhe Wang (chaoslawful)
   * Copyright (C) Yichun Zhang (agentzh)
   */
  
  
  #ifndef DDEBUG
  #define DDEBUG 0
  #endif
  #include "ddebug.h"
  
  
  #include <nginx.h>
  #include <ngx_md5.h>
  #include "ngx_http_lua_common.h"
  #include "ngx_http_lua_cache.h"
  #include "ngx_http_lua_clfactory.h"
  #include "ngx_http_lua_util.h"
  
  
  /**
   * Find code chunk associated with the given key in code cache,
   * and push it to the top of Lua stack if found.
   *
   * Stack layout before call:
   *         |     ...    | <- top
   *
   * Stack layout after call:
   *         | code chunk | <- top
   *         |     ...    |
   *
   * */
  static ngx_int_t
  ngx_http_lua_cache_load_code(lua_State *L, const char *key)
  {
      /*  get code cache table */
      lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key);
      lua_rawget(L, LUA_REGISTRYINDEX);    /*  sp++ */
  
      dd("Code cache table to load: %p", lua_topointer(L, -1));
  
      if (!lua_istable(L, -1)) {
          dd("Error: code cache table to load did not exist!!");
          return NGX_ERROR;
      }
  
      lua_getfield(L, -1, key);    /*  sp++ */
  
      if (lua_isfunction(L, -1)) {
          /*  call closure factory to gen new closure */
          int rc = lua_pcall(L, 0, 1, 0);
  
          if (rc == 0) {
              /*  remove cache table from stack, leave code chunk at
               *  top of stack */
              lua_remove(L, -2);   /*  sp-- */
              return NGX_OK;
          }
      }
  
      dd("Value associated with given key in code cache table is not code "
         "chunk: stack top=%d, top value type=%s\n",
         lua_gettop(L), lua_typename(L, -1));
  
      /*  remove cache table and value from stack */
      lua_pop(L, 2);                                /*  sp-=2 */
  
      return NGX_DECLINED;
  }
  
  
  /**
   * Store the closure factory at the top of Lua stack to code cache, and
   * associate it with the given key. Then generate new closure.
   *
   * Stack layout before call:
   *         | code factory | <- top
   *         |     ...      |
   *
   * Stack layout after call:
   *         | code chunk | <- top
   *         |     ...    |
   *
   * */
  static ngx_int_t
  ngx_http_lua_cache_store_code(lua_State *L, const char *key)
  {
      int rc;
  
      /*  get code cache table */
      lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key);
      lua_rawget(L, LUA_REGISTRYINDEX);
  
      dd("Code cache table to store: %p", lua_topointer(L, -1));
  
      if (!lua_istable(L, -1)) {
          dd("Error: code cache table to load did not exist!!");
          return NGX_ERROR;
      }
  
      lua_pushvalue(L, -2); /* closure cache closure */
      lua_setfield(L, -2, key); /* closure cache */
  
      /*  remove cache table, leave closure factory at top of stack */
      lua_pop(L, 1); /* closure */
  
      /*  call closure factory to generate new closure */
      rc = lua_pcall(L, 0, 1, 0);
      if (rc != 0) {
          dd("Error: failed to call closure factory!!");
          return NGX_ERROR;
      }
  
      return NGX_OK;
  }
  
  
  ngx_int_t
  ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len,
      const u_char *cache_key, const char *name)
  {
      int          rc, n;
      const char  *err = NULL;
  
      n = lua_gettop(L);
  
      dd("XXX cache key: [%s]", cache_key);
  
      if (ngx_http_lua_cache_load_code(L, (char *) cache_key) == NGX_OK) {
          /*  code chunk loaded from cache, sp++ */
          dd("Code cache hit! cache key='%s', stack top=%d, script='%.*s'",
             cache_key, lua_gettop(L), (int) src_len, src);
          return NGX_OK;
      }
  
      dd("Code cache missed! cache key='%s', stack top=%d, script='%.*s'",
         cache_key, lua_gettop(L), (int) src_len, src);
  
      /* load closure factory of inline script to the top of lua stack, sp++ */
      rc = ngx_http_lua_clfactory_loadbuffer(L, (char *) src, src_len, name);
  
      if (rc != 0) {
          /*  Oops! error occured when loading Lua script */
          if (rc == LUA_ERRMEM) {
              err = "memory allocation error";
  
          } else {
              if (lua_isstring(L, -1)) {
                  err = lua_tostring(L, -1);
  
              } else {
                  err = "unknown error";
              }
          }
  
          goto error;
      }
  
      /*  store closure factory and gen new closure at the top of lua stack to
       *  code cache */
      rc = ngx_http_lua_cache_store_code(L, (char *) cache_key);
  
      if (rc != NGX_OK) {
          err = "fail to generate new closure from the closure factory";
          goto error;
      }
  
      return NGX_OK;
  
  error:
      ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
                    "failed to load inlined Lua code: %s", err);
      lua_settop(L, n);
      return NGX_ERROR;
  }
  
  
  ngx_int_t
  ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script,
      const u_char *cache_key)
  {
      int              rc, n;
      u_char          *p;
      u_char           buf[NGX_HTTP_LUA_FILE_KEY_LEN + 1];
      const char      *err = NULL;
  
      n = lua_gettop(L);
  
      /*  calculate digest of script file path */
      if (cache_key == NULL) {
          dd("CACHE file key not pre-calculated...calculating");
          p = ngx_copy(buf, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN);
  
          p = ngx_http_lua_digest_hex(p, script, ngx_strlen(script));
  
          *p = '\0';
          cache_key = buf;
  
      } else {
          dd("CACHE file key already pre-calculated");
      }
  
      dd("XXX cache key for file: [%s]", cache_key);
  
      if (ngx_http_lua_cache_load_code(L, (char *) cache_key) == NGX_OK) {
          /*  code chunk loaded from cache, sp++ */
          dd("Code cache hit! cache key='%s', stack top=%d, file path='%s'",
             cache_key, lua_gettop(L), script);
          return NGX_OK;
      }
  
      dd("Code cache missed! cache key='%s', stack top=%d, file path='%s'",
         cache_key, lua_gettop(L), script);
  
      /*  load closure factory of script file to the top of lua stack, sp++ */
      rc = ngx_http_lua_clfactory_loadfile(L, (char *) script);
  
      if (rc != 0) {
          /*  Oops! error occured when loading Lua script */
          if (rc == LUA_ERRMEM) {
              err = "memory allocation error";
  
          } else {
              if (lua_isstring(L, -1)) {
                  err = lua_tostring(L, -1);
  
              } else {
                  err = "unknown error";
              }
          }
  
          goto error;
      }
  
      /*  store closure factory and gen new closure at the top of lua stack
       *  to code cache */
      rc = ngx_http_lua_cache_store_code(L, (char *) cache_key);
  
      if (rc != NGX_OK) {
          err = "fail to generate new closure from the closure factory";
          goto error;
      }
  
      return NGX_OK;
  
  error:
      ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
                    "failed to load external Lua file: %s", err);
  
      lua_settop(L, n);
      return NGX_ERROR;
  }
  
  /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
  