diff options
Diffstat (limited to 'xlators/bindings/python/src/python.c')
| -rw-r--r-- | xlators/bindings/python/src/python.c | 235 | 
1 files changed, 235 insertions, 0 deletions
diff --git a/xlators/bindings/python/src/python.c b/xlators/bindings/python/src/python.c new file mode 100644 index 000000000..739ef7329 --- /dev/null +++ b/xlators/bindings/python/src/python.c @@ -0,0 +1,235 @@ +/* +   Copyright (c) 2007 Chris AtLee <chris@atlee.ca> +   This file is part of GlusterFS. + +   GlusterFS is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published +   by the Free Software Foundation; either version 3 of the License, +   or (at your option) any later version. + +   GlusterFS 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, see +   <http://www.gnu.org/licenses/>. +*/ + +#include <Python.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs.h" +#include "xlator.h" +#include "logging.h" +#include "defaults.h" + +typedef struct +{ +    char        *scriptname; +    PyObject    *pXlator; +    PyObject    *pScriptModule; +    PyObject    *pGlusterModule; +    PyThreadState *pInterp; + +    PyObject    *pFrameType, *pVectorType, *pFdType; +} python_private_t; + +int32_t +python_writev (call_frame_t *frame, +              xlator_t *this, +              fd_t *fd, +              struct iovec *vector, +              int32_t count,  +              off_t offset) +{ +  python_private_t *priv = (python_private_t *)this->private; +  gf_log("python", GF_LOG_DEBUG, "In writev"); +  if (PyObject_HasAttrString(priv->pXlator, "writev")) +  { + +      PyObject *retval = PyObject_CallMethod(priv->pXlator, "writev", +              "O O O i l", +              PyObject_CallMethod(priv->pFrameType, "from_address", "O&", PyLong_FromVoidPtr, frame), +              PyObject_CallMethod(priv->pFdType, "from_address", "O&", PyLong_FromVoidPtr, fd), +              PyObject_CallMethod(priv->pVectorType, "from_address", "O&", PyLong_FromVoidPtr, vector), +              count, +              offset); +      if (PyErr_Occurred()) +      { +          PyErr_Print(); +      } +      Py_XDECREF(retval); +  } +  else +  { +      return default_writev(frame, this, fd, vector, count, offset); +  } +  return 0; +} + +struct xlator_fops fops = { +    .writev       = python_writev +}; + +struct xlator_mops mops = { +}; + +static PyObject * +AnonModule_FromFile (const char* fname) +{ +    // Get the builtins +    PyThreadState* pThread = PyThreadState_Get(); +    PyObject *pBuiltins = pThread->interp->builtins; + +    if (PyErr_Occurred()) +    { +        PyErr_Print(); +        return NULL; +    } + +    // Create a new dictionary for running code in +    PyObject *pModuleDict = PyDict_New(); +    PyDict_SetItemString(pModuleDict, "__builtins__", pBuiltins); +    Py_INCREF(pBuiltins); + +    // Run the file in the new context +    FILE* fp = fopen(fname, "r"); +    PyRun_File(fp, fname, Py_file_input, pModuleDict, pModuleDict); +    fclose(fp); +    if (PyErr_Occurred()) +    { +        PyErr_Print(); +        Py_DECREF(pModuleDict); +        Py_DECREF(pBuiltins); +        return NULL; +    } + +    // Create an object to hold the new context +    PyRun_String("class ModuleWrapper(object):\n\tpass\n", Py_single_input, pModuleDict, pModuleDict); +    if (PyErr_Occurred()) +    { +        PyErr_Print(); +        Py_DECREF(pModuleDict); +        Py_DECREF(pBuiltins); +        return NULL; +    } +    PyObject *pModule = PyRun_String("ModuleWrapper()", Py_eval_input, pModuleDict, pModuleDict); +    if (PyErr_Occurred()) +    { +        PyErr_Print(); +        Py_DECREF(pModuleDict); +        Py_DECREF(pBuiltins); +        Py_XDECREF(pModule); +        return NULL; +    } + +    // Set the new context's dictionary to the one we used to run the code +    // inside +    PyObject_SetAttrString(pModule, "__dict__", pModuleDict); +    if (PyErr_Occurred()) +    { +        PyErr_Print(); +        Py_DECREF(pModuleDict); +        Py_DECREF(pBuiltins); +        Py_DECREF(pModule); +        return NULL; +    } + +    return pModule; +} + +int32_t +init (xlator_t *this) +{ +  // This is ok to call more than once per process +  Py_InitializeEx(0); + +  if (!this->children) { +    gf_log ("python", GF_LOG_ERROR,  +            "FATAL: python should have exactly one child"); +    return -1; +  } + +  python_private_t *priv = CALLOC (sizeof (python_private_t), 1); +  ERR_ABORT (priv); + +  data_t *scriptname = dict_get (this->options, "scriptname"); +  if (scriptname) { +      priv->scriptname = data_to_str(scriptname); +  } else { +      gf_log("python", GF_LOG_ERROR, +              "FATAL: python requires the scriptname parameter"); +      return -1; +  } + +  priv->pInterp = Py_NewInterpreter(); +     +  // Adjust python's path +  PyObject *syspath = PySys_GetObject("path"); +  PyObject *path = PyString_FromString(GLUSTER_PYTHON_PATH); +  PyList_Append(syspath, path); +  Py_DECREF(path); + +  gf_log("python", GF_LOG_DEBUG, +          "Loading gluster module"); + +  priv->pGlusterModule = PyImport_ImportModule("gluster"); +  if (PyErr_Occurred()) +  { +      PyErr_Print(); +      return -1; +  } + +  priv->pFrameType = PyObject_GetAttrString(priv->pGlusterModule, "call_frame_t"); +  priv->pFdType = PyObject_GetAttrString(priv->pGlusterModule, "fd_t"); +  priv->pVectorType = PyObject_GetAttrString(priv->pGlusterModule, "iovec"); + +  gf_log("python", GF_LOG_DEBUG, "Loading script...%s", priv->scriptname); +   +  priv->pScriptModule = AnonModule_FromFile(priv->scriptname); +  if (!priv->pScriptModule || PyErr_Occurred()) +  { +      gf_log("python", GF_LOG_ERROR, "Error loading %s", priv->scriptname); +      PyErr_Print(); +      return -1; +  } + +  if (!PyObject_HasAttrString(priv->pScriptModule, "xlator")) +  { +      gf_log("python", GF_LOG_ERROR, "%s does not have a xlator attribute", priv->scriptname); +      return -1; +  } +  gf_log("python", GF_LOG_DEBUG, "Instantiating translator"); +  priv->pXlator = PyObject_CallMethod(priv->pScriptModule, "xlator", "O&", +          PyLong_FromVoidPtr, this); +  if (PyErr_Occurred() || !priv->pXlator) +  { +      PyErr_Print(); +      return -1; +  } + +  this->private = priv; + +  gf_log ("python", GF_LOG_DEBUG, "python xlator loaded"); +  return 0; +} + +void  +fini (xlator_t *this) +{ +  python_private_t *priv = (python_private_t*)(this->private); +  Py_DECREF(priv->pXlator); +  Py_DECREF(priv->pScriptModule); +  Py_DECREF(priv->pGlusterModule); +  Py_DECREF(priv->pFrameType); +  Py_DECREF(priv->pFdType); +  Py_DECREF(priv->pVectorType); +  Py_EndInterpreter(priv->pInterp); +  return; +}  | 
