nfs-ganesha 1.4

posixdb_add.c

Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #ifdef _SOLARIS
00006 #include "solaris_port.h"
00007 #endif
00008 
00009 #include "posixdb_internal.h"
00010 #include "posixdb_consistency.h"
00011 #include <string.h>
00012 
00013 fsal_posixdb_status_t fsal_posixdb_add(fsal_posixdb_conn * p_conn,      /* IN */
00014                                        fsal_posixdb_fileinfo_t * p_object_info, /* IN */
00015                                        posixfsal_handle_t * p_parent_directory_handle,  /* IN */
00016                                        fsal_name_t * p_filename,        /* IN */
00017                                        posixfsal_handle_t * p_object_handle /* OUT */ )
00018 {
00019   PGresult *p_res;
00020   char handleid_str[MAX_HANDLEIDSTR_SIZE];
00021   char handlets_str[MAX_HANDLETSSTR_SIZE];
00022   char handleidparent_str[MAX_HANDLEIDSTR_SIZE];
00023   char handletsparent_str[MAX_HANDLETSSTR_SIZE];
00024   char devid_str[MAX_DEVICEIDSTR_SIZE];
00025   char inode_str[MAX_INODESTR_SIZE];
00026   int found;
00027   const char *paramValues[6];
00028   fsal_posixdb_status_t st;
00029 
00030   /*******************
00031    * 1/ sanity check *
00032    *******************/
00033 
00034   /* parent_directory and filename are NULL only if it is the root directory */
00035   if(!p_conn || !p_object_info || !p_object_handle
00036      || (p_filename && !p_parent_directory_handle) || (!p_filename
00037                                                        && p_parent_directory_handle))
00038     ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00039 
00040   CheckConn(p_conn);
00041 
00042   LogFullDebug(COMPONENT_FSAL, "adding entry with parentid=%llu, id=%"PRIu64", name=%s\n",
00043          p_parent_directory_handle ? p_parent_directory_handle->data.id : 0,
00044          p_object_info ? p_object_info->inode : 0,
00045          p_filename ? p_filename->name : "NULL");
00046 
00047   BeginTransaction(p_conn, p_res);
00048 
00049   /*********************************
00050    * 2/ we check the parent handle *
00051    *********************************/
00052 
00053   if(p_parent_directory_handle)
00054     {                           /* the root has no parent */
00055       snprintf(handleidparent_str, MAX_HANDLEIDSTR_SIZE, "%llu",
00056                p_parent_directory_handle->data.id);
00057       snprintf(handletsparent_str, MAX_HANDLETSSTR_SIZE, "%i",
00058                p_parent_directory_handle->data.ts);
00059       paramValues[0] = handleidparent_str;
00060       paramValues[1] = handletsparent_str;
00061       p_res = PQexecPrepared(p_conn, "lookupHandle", 2, paramValues, NULL, NULL, 0);
00062       CheckResult(p_res);
00063 
00064       if(PQntuples(p_res) != 1)
00065         {
00066           /* parent entry not found */
00067           RollbackTransaction(p_conn, p_res);
00068           ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0);
00069         }
00070       PQclear(p_res);
00071     }
00072   /**********************************************************
00073    * 3/ Check if there is an existing Handle for the object *
00074    **********************************************************/
00075   snprintf(devid_str, MAX_DEVICEIDSTR_SIZE, "%llu",
00076            (unsigned long long int)p_object_info->devid);
00077   snprintf(inode_str, MAX_INODESTR_SIZE, "%llu",
00078            (unsigned long long int)p_object_info->inode);
00079   paramValues[0] = devid_str;
00080   paramValues[1] = inode_str;
00081   p_res = PQexecPrepared(p_conn, "lookupHandleByInodeFU", 2, paramValues, NULL, NULL, 0);
00082   CheckResult(p_res);
00083   found = (PQntuples(p_res) == 1);
00084 
00085   if(found)
00086     {                           /* a Handle (that matches devid & inode) already exists */
00087       /* fill 'info' with information about the handle in the database */
00088       posixdb_internal_fillFileinfoFromStrValues(&(p_object_handle->data.info), NULL, NULL, PQgetvalue(p_res, 0, 2), /* nlink */
00089                                                  PQgetvalue(p_res, 0, 3),       /* ctime */
00090                                                  PQgetvalue(p_res, 0, 4)        /* ftype */
00091           );
00092       p_object_handle->data.info.inode = p_object_info->inode;
00093       p_object_handle->data.info.devid = p_object_info->devid;
00094       strncpy(handleid_str, PQgetvalue(p_res, 0, 0), MAX_HANDLEIDSTR_SIZE);
00095       strncpy(handlets_str, PQgetvalue(p_res, 0, 1), MAX_HANDLETSSTR_SIZE);
00096       PQclear(p_res);
00097 
00098       p_object_handle->data.id = atoll(handleid_str);
00099       p_object_handle->data.ts = atoi(handlets_str);
00100 
00101       /* check the consistency of the handle */
00102       if(fsal_posixdb_consistency_check(&(p_object_handle->data.info), p_object_info))
00103         {
00104           /* consistency check failed */
00105           /* p_object_handle has been filled in order to be able to fix the consistency later */
00106           RollbackTransaction(p_conn, p_res);
00107           ReturnCodeDB(ERR_FSAL_POSIXDB_CONSISTENCY, 0);
00108         }
00109 
00110       /* update nlink & ctime if needed */
00111       if(p_object_info->nlink != p_object_handle->data.info.nlink
00112          || p_object_info->ctime != p_object_handle->data.info.ctime)
00113         {
00114           char nlink_str[MAX_NLINKSTR_SIZE];
00115           char ctime_str[MAX_CTIMESTR_SIZE];
00116 
00117           snprintf(nlink_str, MAX_NLINKSTR_SIZE, "%i", p_object_info->nlink);
00118           snprintf(ctime_str, MAX_CTIMESTR_SIZE, "%i", (int)p_object_info->ctime);
00119           paramValues[0] = handleid_str;
00120           paramValues[1] = handlets_str;
00121           paramValues[2] = nlink_str;
00122           paramValues[3] = ctime_str;
00123 
00124           p_object_handle->data.info = *p_object_info;
00125 
00126           p_res = PQexecPrepared(p_conn, "updateHandle", 4, paramValues, NULL, NULL, 0);
00127           CheckCommand(p_res);
00128         }
00129 
00130       fsal_posixdb_UpdateInodeCache(p_object_handle);
00131 
00132     }
00133   else
00134     {                           /* no handle found */
00135       /* Handle does not exist, add a new Handle entry */
00136       char nlink_str[MAX_NLINKSTR_SIZE];
00137       char ctime_str[MAX_CTIMESTR_SIZE];
00138       char ftype_str[MAX_FTYPESTR_SIZE];
00139       PQclear(p_res);
00140 
00141       p_object_handle->data.ts = (int)time(NULL);
00142       p_object_handle->data.info = *p_object_info;
00143       snprintf(handlets_str, MAX_HANDLETSSTR_SIZE, "%i", p_object_handle->data.ts);
00144       snprintf(nlink_str, MAX_NLINKSTR_SIZE, "%i", p_object_info->nlink);
00145       snprintf(ctime_str, MAX_CTIMESTR_SIZE, "%i", (int)p_object_info->ctime);
00146       snprintf(ftype_str, MAX_CTIMESTR_SIZE, "%i", (int)p_object_info->ftype);
00147 
00148       paramValues[0] = devid_str;
00149       paramValues[1] = inode_str;
00150       paramValues[2] = handlets_str;
00151       paramValues[3] = nlink_str;
00152       paramValues[4] = ctime_str;
00153       paramValues[5] = ftype_str;
00154 
00155       p_res = PQexecPrepared(p_conn, "insertHandle", 6, paramValues, NULL, NULL, 0);
00156       CheckCommand(p_res);
00157 
00158       PQclear(p_res);
00159 
00160       p_res =
00161           PQexecPrepared(p_conn, "lookupHandleByInodeFU", 2, paramValues, NULL, NULL, 0);
00162       CheckResult(p_res);
00163 
00164       strncpy(handleid_str, PQgetvalue(p_res, 0, 0), MAX_HANDLEIDSTR_SIZE);
00165       strncpy(handlets_str, PQgetvalue(p_res, 0, 1), MAX_HANDLETSSTR_SIZE);
00166       p_object_handle->data.id = atoll(PQgetvalue(p_res, 0, 0));
00167       PQclear(p_res);
00168 
00169       /* now, we have the handle id */
00170       fsal_posixdb_UpdateInodeCache(p_object_handle);
00171 
00172     }
00173 
00174   /************************************************
00175    * add (or update) an entry in the Parent table *
00176    ************************************************/
00177   paramValues[0] = p_parent_directory_handle ? handleidparent_str : handleid_str;
00178   paramValues[1] = p_parent_directory_handle ? handletsparent_str : handlets_str;
00179   paramValues[2] = p_filename ? p_filename->name : "";
00180   p_res = PQexecPrepared(p_conn, "lookupParent", 3, paramValues, NULL, NULL, 0);
00181   CheckResult(p_res);
00182   /* p-res contains handleid & handlets */
00183   found = (PQntuples(p_res) == 1);
00184   paramValues[3] = handleid_str;
00185   paramValues[4] = handlets_str;
00186   if(found)
00187     {
00188       /* update the Parent entry if necessary (there entry exists with another handle) */
00189       if((fsal_u64_t) atoll(PQgetvalue(p_res, 0, 0)) != p_object_handle->data.id
00190          || atoi(PQgetvalue(p_res, 0, 1)) != p_object_handle->data.ts)
00191         {
00192           /* steps :
00193              - check the nlink value of the Parent entry to be overwritten
00194              - if nlink = 1, then we can delete the handle.
00195              else we have to update it (nlink--) : that is done by fsal_posixdb_deleteParent
00196              - update the handle of the entry
00197            */
00198           char bad_handleid_str[MAX_HANDLEIDSTR_SIZE];
00199           char bad_handlets_str[MAX_HANDLETSSTR_SIZE];
00200           int nlink;
00201 
00202           strncpy(bad_handleid_str, PQgetvalue(p_res, 0, 0), MAX_HANDLEIDSTR_SIZE);
00203           strncpy(bad_handlets_str, PQgetvalue(p_res, 0, 1), MAX_HANDLETSSTR_SIZE);
00204           PQclear(p_res);       /* clear old res before a new query */
00205 
00206           /* check the nlink value of the entry to be updated */
00207           paramValues[0] = handleidparent_str;
00208           paramValues[1] = handletsparent_str;
00209           p_res = PQexecPrepared(p_conn, "lookupHandleFU", 2, paramValues, NULL, NULL, 0);
00210           CheckResult(p_res);
00211 
00212           found = (PQntuples(p_res) == 1);
00213 
00214           if(found)
00215             {                   /* we have retrieved the handle information of the bad entry */
00216               nlink = atoi(PQgetvalue(p_res, 0, 4));
00217               PQclear(p_res);   /* clear old res before a new query */
00218 
00219               /* a Parent entry already exists, we delete it */
00220 
00221               st = fsal_posixdb_deleteParent(p_conn, bad_handleid_str, bad_handlets_str,
00222                                              p_parent_directory_handle ?
00223                                              handleidparent_str : handleid_str,
00224                                              p_parent_directory_handle ?
00225                                              handletsparent_str : handlets_str,
00226                                              p_filename ? p_filename->name : "", nlink);
00227               if(FSAL_POSIXDB_IS_ERROR(st))
00228                 {
00229                   RollbackTransaction(p_conn, p_res);
00230                   return st;
00231                 }
00232             }
00233           else
00234             {                   /* the Handle line has been deleted */
00235               PQclear(p_res);   /* clear old res before a new query */
00236             }
00237 
00238           /* the bad entry has been deleted. Now we had a new Parent entry */
00239           goto add_new_parent_entry;
00240 
00241         }
00242       else
00243         {
00244           /* a Parent entry exists with our handle, nothing to do */
00245           PQclear(p_res);
00246         }
00247     }
00248   else
00249     {
00250       /* add a Parent entry */
00251       PQclear(p_res);
00252  add_new_parent_entry:
00253       paramValues[0] = p_parent_directory_handle ? handleidparent_str : handleid_str;
00254       paramValues[1] = p_parent_directory_handle ? handletsparent_str : handlets_str;
00255       paramValues[2] = p_filename ? p_filename->name : "";
00256       paramValues[3] = handleid_str;
00257       paramValues[4] = handlets_str;
00258 
00259       p_res = PQexecPrepared(p_conn, "insertParent", 5, paramValues, NULL, NULL, 0);
00260       CheckCommand(p_res);
00261       PQclear(p_res);
00262       /* XXX : is it possible to have unique key violation ? */
00263     }
00264 
00265   EndTransaction(p_conn, p_res);
00266 
00267   ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00268 }