sb_map
authorRobert Haas <rhaas@postgresql.org>
Tue, 11 Mar 2014 19:39:10 +0000 (15:39 -0400)
committerRobert Haas <rhaas@postgresql.org>
Tue, 11 Mar 2014 19:39:10 +0000 (15:39 -0400)
src/backend/utils/mmgr/Makefile
src/backend/utils/mmgr/sb_map.c [new file with mode: 0644]
src/include/utils/sb_map.h [new file with mode: 0644]

index 20973af3ca9758c905e8e16ccb4cc51de8799511..e4086cc3f29ed34e0a05c77425f2e71b7601798b 100644 (file)
@@ -12,6 +12,6 @@ subdir = src/backend/utils/mmgr
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = aset.o freepage.o mcxt.o portalmem.o
+OBJS = aset.o freepage.o mcxt.o portalmem.o sb_map.o
 
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/utils/mmgr/sb_map.c b/src/backend/utils/mmgr/sb_map.c
new file mode 100644 (file)
index 0000000..4c3ea39
--- /dev/null
@@ -0,0 +1,119 @@
+/*-------------------------------------------------------------------------
+ *
+ * sb_map.c
+ *       Superblock allocator page-mapping infrastructure.
+ *
+ * The superblock allocator does not store metadata with each chunk, and
+ * therefore needs a way to find the metadata given only the pointer
+ * address.  The first step is to translate the pointer address to a
+ * an offset relative to some base address, from which a page number
+ * can be calculated.  Then, this module is reponsible for mapping the
+ * page number to an offset with the chunk where the associated span
+ * object is stored.  We do this in the simplest possible way: one big
+ * array.
+ *
+ * Span metadata is stored within the same chunk of memory as the span
+ * itself.  Therefore, we can assume that the offset is less than 4GB
+ * whenever we're managing less than 4GB of pages, and use 4 byte
+ * offsets.  When we're managing more than 4GB of pages, we use 8 byte
+ * offsets.  (This could probably be optimized; for example, we could use
+ * 6 byte offsets for allocation sizes up to 256TB; also, if we assumed
+ * that the span object must itself be 2, 4, or 8 byte aligned, we could
+ * extend the cutoff point for offsets of any given length by a similar
+ * multiple.  It's not clear that the extra math would be worthwhile.)
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/utils/sb_map.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "storage/shmem.h"
+#include "utils/freepage.h"
+#include "utils/sb_map.h"
+
+const uint64 maxpages_4b = UINT64CONST(0x100000000) / FPM_PAGE_SIZE;
+
+struct sb_map
+{
+       Size    npages;
+};
+
+/* Map layout for segments less than 4GB. */
+typedef struct sb_map32
+{
+       sb_map  hdr;
+       uint32  map[FLEXIBLE_ARRAY_MEMBER];
+} sb_map32;
+
+/* Map layout for segments less than 8GB. */
+typedef struct sb_map64
+{
+       sb_map  hdr;
+       uint64  map[FLEXIBLE_ARRAY_MEMBER];
+} sb_map64;
+
+/*
+ * Compute the amount of space required for an sb_map covering a given
+ * number of pages.  Note we assume that the maximum offset we'll be asked
+ * to store is governed by that number of pages also.
+ */
+Size
+sb_map_size(Size npages)
+{
+       Size    map_bytes;
+
+       if (npages < maxpages_4b)
+               map_bytes = add_size(offsetof(sb_map32, map),
+                                                        mul_size(npages, sizeof(uint32)));
+       else
+               map_bytes = add_size(offsetof(sb_map64, map),
+                                                        mul_size(npages, sizeof(uint64)));
+
+       return map_bytes;
+}
+
+/*
+ * Initialize an sb_map.  Storage is provided by the caller.  Note that we
+ * don't zero the array; the caller shouldn't try to get a value that hasn't
+ * been set.
+ */
+void
+sb_map_initialize(sb_map *m, Size npages)
+{
+       m->npages = npages;
+}
+
+/*
+ * Store a value into an sb_map.
+ */
+void
+sb_map_set(sb_map *m, Size pageno, Size offset)
+{
+       Assert(pageno < m->npages);
+       Assert(offset / FPM_PAGE_SIZE < m->npages);
+
+       if (m->npages < maxpages_4b)
+               ((sb_map32 *) m)->map[pageno] = (uint32) offset;
+       else
+               ((sb_map64 *) m)->map[pageno] = (uint32) offset;
+}
+
+/*
+ * Get a value from an sb_map.  Getting a value not previously stored will
+ * produce an undefined result, so don't do that.
+ */
+Size
+sb_map_get(sb_map *m, Size pageno)
+{
+       Assert(pageno < m->npages);
+
+       if (m->npages < maxpages_4b)
+               return ((sb_map32 *) m)->map[pageno];
+       else
+               return ((sb_map64 *) m)->map[pageno];
+}
diff --git a/src/include/utils/sb_map.h b/src/include/utils/sb_map.h
new file mode 100644 (file)
index 0000000..402a452
--- /dev/null
@@ -0,0 +1,24 @@
+/*-------------------------------------------------------------------------
+ *
+ * sb_map.h
+ *       Superblock allocator page-mapping infrastructure.
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/utils/sb_map.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef SB_MAP_H
+#define SB_MAP_H
+
+typedef struct sb_map sb_map;
+
+extern Size sb_map_size(Size npages);
+extern void sb_map_initialize(sb_map *, Size npages);
+extern void sb_map_set(sb_map *, Size pageno, Size offset);
+extern Size sb_map_get(sb_map *, Size pageno);
+
+#endif /* SB_MAP_H */