Remove arbitrary limit on number of simultaneously open large objects.
authorTom Lane
Tue, 24 Oct 2000 03:14:08 +0000 (03:14 +0000)
committerTom Lane
Tue, 24 Oct 2000 03:14:08 +0000 (03:14 +0000)
This used to make some sense under the old implementation, but now an
open LO is pretty darn cheap, so why restrict it?

src/backend/libpq/be-fsstubs.c

index 7eff84e5d3322af2feff7969c6dc144b6aeffe08..a379bd05e8d9617e785c8147e5ad0e73921dd599 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.55 2000/10/24 01:38:26 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.56 2000/10/24 03:14:08 tgl Exp $
  *
  * NOTES
  *   This should be moved to a more appropriate place.  It is here
 /* [PA] is Pascal André  */
 
 /*#define FSDB 1*/
-#define MAX_LOBJ_FDS   256
 #define BUFSIZE            8192
 
 /*
- * LO "FD"s are indexes into this array.
+ * LO "FD"s are indexes into the cookies array.
+ *
  * A non-null entry is a pointer to a LargeObjectDesc allocated in the
- * LO private memory context.
+ * LO private memory context.  The cookies array itself is also dynamically
+ * allocated in that context.  Its current allocated size is cookies_len
+ * entries, of which any unused entries will be NULL.
  */
-static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
+static LargeObjectDesc **cookies = NULL;
+static int cookies_size = 0;
 
 static MemoryContext fscxt = NULL;
 
@@ -104,14 +107,8 @@ lo_open(PG_FUNCTION_ARGS)
 
    fd = newLOfd(lobjDesc);
 
-   /* switch context back to orig. */
    MemoryContextSwitchTo(currentContext);
 
-#if FSDB
-   if (fd < 0)                 /* newLOfd couldn't find a slot */
-       elog(NOTICE, "Out of space for large object FDs");
-#endif
-
    PG_RETURN_INT32(fd);
 }
 
@@ -121,15 +118,10 @@ lo_close(PG_FUNCTION_ARGS)
    int32       fd = PG_GETARG_INT32(0);
    MemoryContext currentContext;
 
-   if (fd < 0 || fd >= MAX_LOBJ_FDS)
-   {
-       elog(ERROR, "lo_close: large obj descriptor (%d) out of range", fd);
-       PG_RETURN_INT32(-2);
-   }
-   if (cookies[fd] == NULL)
+   if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
    {
        elog(ERROR, "lo_close: invalid large obj descriptor (%d)", fd);
-       PG_RETURN_INT32(-3);
+       PG_RETURN_INT32(-1);
    }
 #if FSDB
    elog(NOTICE, "lo_close(%d)", fd);
@@ -162,15 +154,10 @@ lo_read(int fd, char *buf, int len)
    MemoryContext currentContext;
    int         status;
 
-   if (fd < 0 || fd >= MAX_LOBJ_FDS)
-   {
-       elog(ERROR, "lo_read: large obj descriptor (%d) out of range", fd);
-       return -2;
-   }
-   if (cookies[fd] == NULL)
+   if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
    {
        elog(ERROR, "lo_read: invalid large obj descriptor (%d)", fd);
-       return -3;
+       return -1;
    }
 
    Assert(fscxt != NULL);
@@ -189,15 +176,10 @@ lo_write(int fd, char *buf, int len)
    MemoryContext currentContext;
    int         status;
 
-   if (fd < 0 || fd >= MAX_LOBJ_FDS)
-   {
-       elog(ERROR, "lo_write: large obj descriptor (%d) out of range", fd);
-       return -2;
-   }
-   if (cookies[fd] == NULL)
+   if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
    {
        elog(ERROR, "lo_write: invalid large obj descriptor (%d)", fd);
-       return -3;
+       return -1;
    }
 
    Assert(fscxt != NULL);
@@ -220,15 +202,10 @@ lo_lseek(PG_FUNCTION_ARGS)
    MemoryContext currentContext;
    int         status;
 
-   if (fd < 0 || fd >= MAX_LOBJ_FDS)
-   {
-       elog(ERROR, "lo_lseek: large obj descriptor (%d) out of range", fd);
-       PG_RETURN_INT32(-2);
-   }
-   if (cookies[fd] == NULL)
+   if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
    {
        elog(ERROR, "lo_lseek: invalid large obj descriptor (%d)", fd);
-       PG_RETURN_INT32(-3);
+       PG_RETURN_INT32(-1);
    }
 
    Assert(fscxt != NULL);
@@ -280,15 +257,10 @@ lo_tell(PG_FUNCTION_ARGS)
 {
    int32       fd = PG_GETARG_INT32(0);
 
-   if (fd < 0 || fd >= MAX_LOBJ_FDS)
-   {
-       elog(ERROR, "lo_tell: large object descriptor (%d) out of range", fd);
-       PG_RETURN_INT32(-2);
-   }
-   if (cookies[fd] == NULL)
+   if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
    {
        elog(ERROR, "lo_tell: invalid large object descriptor (%d)", fd);
-       PG_RETURN_INT32(-3);
+       PG_RETURN_INT32(-1);
    }
 
    /*
@@ -304,13 +276,30 @@ lo_unlink(PG_FUNCTION_ARGS)
 {
    Oid         lobjId = PG_GETARG_OID(0);
 
+   /*
+    * If there are any open LO FDs referencing that ID, close 'em.
+    */
+   if (fscxt != NULL)
+   {
+       MemoryContext currentContext;
+       int         i;
+
+       currentContext = MemoryContextSwitchTo(fscxt);
+       for (i = 0; i < cookies_size; i++)
+       {
+           if (cookies[i] != NULL && cookies[i]->id == lobjId)
+           {
+               inv_close(cookies[i]);
+               deleteLOfd(i);
+           }
+       }
+       MemoryContextSwitchTo(currentContext);
+   }
+
    /*
     * inv_drop does not need a context switch, indeed it doesn't touch
     * any LO-specific data structures at all.  (Again, that's probably
     * more than this module ought to be assuming.)
-    *
-    * XXX there ought to be some code to clean up any open LO FDs that
-    * reference the specified LO... as is, they remain "open".
     */
    PG_RETURN_INT32(inv_drop(lobjId));
 }
@@ -502,7 +491,7 @@ lo_commit(bool isCommit)
     * Clean out still-open index scans (not necessary if aborting) and
     * clear cookies array so that LO fds are no longer good.
     */
-   for (i = 0; i < MAX_LOBJ_FDS; i++)
+   for (i = 0; i < cookies_size; i++)
    {
        if (cookies[i] != NULL)
        {
@@ -512,6 +501,10 @@ lo_commit(bool isCommit)
        }
    }
 
+   /* Needn't actually pfree since we're about to zap context */
+   cookies = NULL;
+   cookies_size = 0;
+
    MemoryContextSwitchTo(currentContext);
 
    /* Release the LO memory context to prevent permanent memory leaks. */
@@ -527,18 +520,45 @@ lo_commit(bool isCommit)
 static int
 newLOfd(LargeObjectDesc *lobjCookie)
 {
-   int         i;
+   int         i,
+               newsize;
 
-   for (i = 0; i < MAX_LOBJ_FDS; i++)
+   /* Try to find a free slot */
+   for (i = 0; i < cookies_size; i++)
    {
-
        if (cookies[i] == NULL)
        {
            cookies[i] = lobjCookie;
            return i;
        }
    }
-   return -1;
+
+   /* No free slot, so make the array bigger */
+   if (cookies_size <= 0)
+   {
+       /* First time through, arbitrarily make 64-element array */
+       i = 0;
+       newsize = 64;
+       cookies = (LargeObjectDesc **)
+           palloc(newsize * sizeof(LargeObjectDesc *));
+       MemSet(cookies, 0, newsize * sizeof(LargeObjectDesc *));
+       cookies_size = newsize;
+   }
+   else
+   {
+       /* Double size of array */
+       i = cookies_size;
+       newsize = cookies_size * 2;
+       cookies = (LargeObjectDesc **)
+           repalloc(cookies, newsize * sizeof(LargeObjectDesc *));
+       MemSet(cookies + cookies_size, 0,
+              (newsize - cookies_size) * sizeof(LargeObjectDesc *));
+       cookies_size = newsize;
+   }
+
+   Assert(cookies[i] == NULL);
+   cookies[i] = lobjCookie;
+   return i;
 }
 
 static void