You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@age.apache.org by jg...@apache.org on 2022/02/10 02:05:55 UTC

[incubator-age] branch master updated: Rebase VLE code

This is an automated email from the ASF dual-hosted git repository.

jgemignani pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-age.git


The following commit(s) were added to refs/heads/master by this push:
     new fada9c9  Rebase VLE code
fada9c9 is described below

commit fada9c9cbe348e10593b6647d3bdb5864a719a1b
Author: John Gemignani <jr...@gmail.com>
AuthorDate: Fri Feb 4 17:22:55 2022 -0800

    Rebase VLE code
    
    Rebased the VLE code -
    
    Pulled out the graphid list and stack data structures used by the
    VLE so that they may be used by others. This also provides a good
    place for other graph related data structures to be stored.
    
    Pulled out the graph creation and management routines and the graph
    vertex and edge data structures to allow for other uses beyond VLE.
    
    The data structures for the graph were purposely not moved in with
    the other data structures as they are vital to the graph creation
    and management logic. It might be useful to eventually refactor this
    to expand what a graph may contain. But, for now, it was left alone.
    
    The header files: age_global_graph.h and age_graphid_ds.h have the
    interfaces for these functions and are designed to hide the
    implementation from the user.
    
    All regression tests completed without issue.
---
 Makefile                                          |    4 +-
 src/backend/utils/adt/age_global_graph.c          |  822 +++++++++++++++
 src/backend/utils/adt/age_graphid_ds.c            |  242 +++++
 src/backend/utils/adt/{agtype_vle.c => age_vle.c} | 1161 +++------------------
 src/backend/utils/adt/agtype.c                    |    4 +-
 src/include/utils/age_global_graph.h              |   60 ++
 src/include/utils/age_graphid_ds.h                |   69 ++
 src/include/utils/{agtype_vle.h => age_vle.h}     |    3 +-
 8 files changed, 1326 insertions(+), 1039 deletions(-)

diff --git a/Makefile b/Makefile
index 19c460e..94a2a0f 100644
--- a/Makefile
+++ b/Makefile
@@ -48,12 +48,14 @@ OBJS = src/backend/age.o \
        src/backend/parser/cypher_parse_agg.o \
        src/backend/parser/cypher_parse_node.o \
        src/backend/parser/cypher_parser.o \
+       src/backend/utils/adt/age_graphid_ds.o \
        src/backend/utils/adt/agtype.o \
        src/backend/utils/adt/agtype_ext.o \
        src/backend/utils/adt/agtype_ops.o \
        src/backend/utils/adt/agtype_parser.o \
        src/backend/utils/adt/agtype_util.o \
-       src/backend/utils/adt/agtype_vle.o \
+       src/backend/utils/adt/age_global_graph.o \
+       src/backend/utils/adt/age_vle.o \
        src/backend/utils/adt/cypher_funcs.o \
        src/backend/utils/adt/ag_float8_supp.o \
        src/backend/utils/adt/graphid.o \
diff --git a/src/backend/utils/adt/age_global_graph.c b/src/backend/utils/adt/age_global_graph.c
new file mode 100644
index 0000000..1d68811
--- /dev/null
+++ b/src/backend/utils/adt/age_global_graph.c
@@ -0,0 +1,822 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "postgres.h"
+
+#include "catalog/namespace.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/rel.h"
+#include "utils/snapmgr.h"
+#include "commands/label_commands.h"
+
+#include "utils/age_global_graph.h"
+#include "utils/agtype.h"
+#include "catalog/ag_graph.h"
+#include "catalog/ag_label.h"
+#include "utils/graphid.h"
+#include "utils/age_graphid_ds.h"
+
+/* defines */
+#define VERTEX_HTAB_NAME "Vertex to edge lists " /* added a space at end for */
+#define EDGE_HTAB_NAME "Edge to vertex mapping " /* the graph name to follow */
+#define VERTEX_HTAB_INITIAL_SIZE 1000000
+#define EDGE_HTAB_INITIAL_SIZE 1000000
+
+/* internal data structures implementation */
+/* vertex entry for the vertex_hastable */
+typedef struct vertex_entry
+{
+    graphid vertex_id;             /* vertex id, it is also the hash key */
+    ListGraphId *edges;            /* A list of all (entering & exiting) edges'
+                                    * graphids (int64s). */
+    Oid vertex_label_table_oid;    /* the label table oid */
+    Datum vertex_properties;       /* datum property value */
+} vertex_entry;
+
+/* edge entry for the edge_hashtable */
+typedef struct edge_entry
+{
+    graphid edge_id;               /* edge id, it is also the hash key */
+    Oid edge_label_table_oid;      /* the label table oid */
+    Datum edge_properties;         /* datum property value */
+    graphid start_vertex_id;       /* start vertex */
+    graphid end_vertex_id;         /* end vertex */
+} edge_entry;
+
+/*
+ * GRAPH global context per graph. They are chained together via next.
+ * Be aware that the global pointer will point to the root BUT that
+ * the root will change as new graphs are added to the top.
+ */
+typedef struct GRAPH_global_context
+{
+    char *graph_name;              /* graph name */
+    Oid graph_oid;                 /* graph oid for searching */
+    HTAB *vertex_hashtable;        /* hashtable to hold vertex edge lists */
+    HTAB *edge_hashtable;          /* hashtable to hold edge to vertex map */
+    TransactionId xmin;            /* transaction ids for this graph */
+    TransactionId xmax;
+    int64 num_loaded_vertices;     /* number of loaded vertices in this graph */
+    int64 num_loaded_edges;        /* number of loaded edges in this graph */
+    ListGraphId *vertices;         /* vertices for vertex hashtable cleanup */
+    struct GRAPH_global_context *next; /* next graph */
+} GRAPH_global_context;
+
+/* global variable to hold the per process GRAPH global context */
+static GRAPH_global_context *global_graph_contexts = NULL;
+
+/* declarations */
+/* GRAPH global context functions */
+static void free_specific_GRAPH_global_context(GRAPH_global_context *ggctx);
+static void create_GRAPH_global_hashtables(GRAPH_global_context *ggctx);
+static void load_GRAPH_global_hashtables(GRAPH_global_context *ggctx);
+static void load_vertex_hashtable(GRAPH_global_context *ggctx);
+static void load_edge_hashtable(GRAPH_global_context *ggctx);
+static void freeze_GRAPH_global_hashtables(GRAPH_global_context *ggctx);
+static List *get_ag_labels_names(Snapshot snapshot, Oid graph_oid,
+                                 char label_type);
+static bool insert_edge(GRAPH_global_context *ggctx, graphid edge_id,
+                        Datum edge_properties, graphid start_vertex_id,
+                        graphid end_vertex_id, Oid edge_label_table_oid);
+static bool insert_vertex_edge(GRAPH_global_context *ggctx, graphid vertex_id,
+                               graphid edge_id);
+static bool insert_vertex_entry(GRAPH_global_context *ggctx, graphid vertex_id,
+                                Oid vertex_label_table_oid,
+                                Datum vertex_properties);
+/* definitions */
+/*
+ * Helper function to create the global vertex and edge hashtables. One
+ * hashtable will hold the vertex, its edges (both incoming and exiting) as a
+ * list, and its properties datum. The other hashtable will hold the edge, its
+ * properties datum, and its source and target vertex.
+ */
+static void create_GRAPH_global_hashtables(GRAPH_global_context *ggctx)
+{
+    HASHCTL vertex_ctl;
+    HASHCTL edge_ctl;
+    char *graph_name = NULL;
+    char *vhn = NULL;
+    char *ehn = NULL;
+    int glen;
+    int vlen;
+    int elen;
+
+    /* get the graph name and length */
+    graph_name = ggctx->graph_name;
+    glen = strlen(graph_name);
+    /* get the vertex htab name length */
+    vlen = strlen(VERTEX_HTAB_NAME);
+    /* get the edge htab name length */
+    elen = strlen(EDGE_HTAB_NAME);
+    /* allocate the space and build the names */
+    vhn = palloc0(vlen + glen + 1);
+    ehn = palloc0(elen + glen + 1);
+    /* copy in the names */
+    strcpy(vhn, VERTEX_HTAB_NAME);
+    strcpy(ehn, EDGE_HTAB_NAME);
+    /* add in the graph name */
+    vhn = strncat(vhn, graph_name, glen);
+    ehn = strncat(ehn, graph_name, glen);
+
+    /* initialize the vertex hashtable */
+    MemSet(&vertex_ctl, 0, sizeof(vertex_ctl));
+    vertex_ctl.keysize = sizeof(int64);
+    vertex_ctl.entrysize = sizeof(vertex_entry);
+    vertex_ctl.hash = tag_hash;
+    ggctx->vertex_hashtable = hash_create(vhn, VERTEX_HTAB_INITIAL_SIZE,
+                                          &vertex_ctl,
+                                          HASH_ELEM | HASH_FUNCTION);
+
+    /* initialize the edge hashtable */
+    MemSet(&edge_ctl, 0, sizeof(edge_ctl));
+    edge_ctl.keysize = sizeof(int64);
+    edge_ctl.entrysize = sizeof(edge_entry);
+    edge_ctl.hash = tag_hash;
+    ggctx->edge_hashtable = hash_create(ehn, EDGE_HTAB_INITIAL_SIZE, &edge_ctl,
+                                        HASH_ELEM | HASH_FUNCTION);
+}
+
+/* helper function to get a List of all label names for the specified graph */
+static List *get_ag_labels_names(Snapshot snapshot, Oid graph_oid,
+                                 char label_type)
+{
+    List *labels = NIL;
+    ScanKeyData scan_keys[2];
+    Relation ag_label;
+    HeapScanDesc scan_desc;
+    HeapTuple tuple;
+    TupleDesc tupdesc;
+
+    /* we need a valid snapshot */
+    Assert(snapshot != NULL);
+
+    /* setup scan keys to get all edges for the given graph oid */
+    ScanKeyInit(&scan_keys[1], Anum_ag_label_graph, BTEqualStrategyNumber,
+                F_OIDEQ, ObjectIdGetDatum(graph_oid));
+    ScanKeyInit(&scan_keys[0], Anum_ag_label_kind, BTEqualStrategyNumber,
+                F_CHAREQ, CharGetDatum(label_type));
+
+    /* setup the table to be scanned, ag_label in this case */
+    ag_label = heap_open(ag_label_relation_id(), ShareLock);
+    scan_desc = heap_beginscan(ag_label, snapshot, 2, scan_keys);
+
+    /* get the tupdesc - we don't need to release this one */
+    tupdesc = RelationGetDescr(ag_label);
+    /* bail if the number of columns differs - this table has 5 */
+    Assert(tupdesc->natts == Natts_ag_label);
+
+    /* get all of the label names */
+    while((tuple = heap_getnext(scan_desc, ForwardScanDirection)) != NULL)
+    {
+        Name label;
+        bool is_null = false;
+
+        /* something is wrong if this tuple isn't valid */
+        Assert(HeapTupleIsValid(tuple));
+        /* get the label name */
+        label = DatumGetName(heap_getattr(tuple, Anum_ag_label_name, tupdesc,
+                                          &is_null));
+        Assert(!is_null);
+        /* add it to our list */
+        labels = lappend(labels, label);
+    }
+
+    /* close up scan */
+    heap_endscan(scan_desc);
+    heap_close(ag_label, ShareLock);
+
+    return labels;
+}
+
+/*
+ * Helper function to insert one edge/edge->vertex, key/value pair, in the
+ * current GRAPH global edge hashtable.
+ */
+static bool insert_edge(GRAPH_global_context *ggctx, graphid edge_id,
+                        Datum edge_properties, graphid start_vertex_id,
+                        graphid end_vertex_id, Oid edge_label_table_oid)
+{
+    edge_entry *value = NULL;
+    bool found = false;
+
+    /* search for the edge */
+    value = (edge_entry *)hash_search(ggctx->edge_hashtable, (void *)&edge_id,
+                                      HASH_ENTER, &found);
+    /*
+     * If we found the key, either we have a duplicate, or we made a mistake and
+     * inserted it already. Either way, this isn't good so don't insert it and
+     * return false. Likewise, if the value returned is NULL, don't do anything,
+     * just return false. This way the caller can decide what to do.
+     */
+    if (found || value == NULL)
+    {
+        return false;
+    }
+
+    /* not sure if we really need to zero out the entry, as we set everything */
+    MemSet(value, 0, sizeof(edge_entry));
+
+    /*
+     * Set the edge id - this is important as this is the hash key value used
+     * for hash function collisions.
+     */
+    value->edge_id = edge_id;
+    value->edge_properties = edge_properties;
+    value->start_vertex_id = start_vertex_id;
+    value->end_vertex_id = end_vertex_id;
+    value->edge_label_table_oid = edge_label_table_oid;
+
+    /* increment the number of loaded edges */
+    ggctx->num_loaded_edges++;
+
+    return true;
+}
+
+/*
+ * Helper function to insert an entire vertex into the current GRAPH global
+ * vertex hashtable.
+ */
+static bool insert_vertex_entry(GRAPH_global_context *ggctx, graphid vertex_id,
+                                Oid vertex_label_table_oid,
+                                Datum vertex_properties)
+{
+    vertex_entry *ve = NULL;
+    bool found = false;
+
+    /* search for the vertex */
+    ve = (vertex_entry *)hash_search(ggctx->vertex_hashtable,
+                                     (void *)&vertex_id, HASH_ENTER, &found);
+    /* we should never have duplicates */
+    Assert(!found);
+
+    /* again, MemSet may not be needed here */
+    MemSet(ve, 0, sizeof(vertex_entry));
+
+    /*
+     * Set the vertex id - this is important as this is the hash key value
+     * used for hash function collisions.
+     */
+    ve->vertex_id = vertex_id;
+    /* set the label table oid for this vertex */
+    ve->vertex_label_table_oid = vertex_label_table_oid;
+    /* set the datum vertex properties */
+    ve->vertex_properties = vertex_properties;
+    /* set the NIL edge list */
+    ve->edges = NULL;
+
+    /* we also need to store the vertex id for clean up of vertex lists */
+    ggctx->vertices = append_graphid(ggctx->vertices, vertex_id);
+
+    /* increment the number of loaded vertices */
+    ggctx->num_loaded_vertices++;
+
+    return true;
+}
+
+/*
+ * Helper function to append one edge to an existing vertex in the current
+ * global vertex hashtable.
+ */
+static bool insert_vertex_edge(GRAPH_global_context *ggctx, graphid vertex_id,
+                               graphid edge_id)
+{
+    vertex_entry *value = NULL;
+    bool found = false;
+
+    /* search for the vertex */
+    value = (vertex_entry *)hash_search(ggctx->vertex_hashtable,
+                                        (void *)&vertex_id, HASH_FIND, &found);
+    /* vertices were preloaded so it must be there */
+    Assert(found);
+
+    /* add the edge to the edge list */
+    value->edges = append_graphid(value->edges, edge_id);
+
+    return true;
+}
+
+/* helper routine to load all vertices into the GRAPH global vertex hashtable */
+static void load_vertex_hashtable(GRAPH_global_context *ggctx)
+{
+    Oid graph_oid;
+    Oid graph_namespace_oid;
+    Snapshot snapshot;
+    List *vertex_label_names = NIL;
+    ListCell *lc;
+
+    /* get the specific graph OID and namespace (schema) OID */
+    graph_oid = ggctx->graph_oid;
+    graph_namespace_oid = get_namespace_oid(ggctx->graph_name, false);
+    /* get the active snapshot */
+    snapshot = GetActiveSnapshot();
+    /* get the names of all of the vertex label tables */
+    vertex_label_names = get_ag_labels_names(snapshot, graph_oid,
+                                             LABEL_TYPE_VERTEX);
+    /* go through all vertex label tables in list */
+    foreach (lc, vertex_label_names)
+    {
+        Relation graph_vertex_label;
+        HeapScanDesc scan_desc;
+        HeapTuple tuple;
+        char *vertex_label_name;
+        Oid vertex_label_table_oid;
+        TupleDesc tupdesc;
+
+        /* get the vertex label name */
+        vertex_label_name = lfirst(lc);
+        /* get the vertex label name's OID */
+        vertex_label_table_oid = get_relname_relid(vertex_label_name,
+                                                   graph_namespace_oid);
+        /* open the relation (table) and begin the scan */
+        graph_vertex_label = heap_open(vertex_label_table_oid, ShareLock);
+        scan_desc = heap_beginscan(graph_vertex_label, snapshot, 0, NULL);
+        /* get the tupdesc - we don't need to release this one */
+        tupdesc = RelationGetDescr(graph_vertex_label);
+        /* bail if the number of columns differs */
+        if (tupdesc->natts != 2)
+        {
+            ereport(ERROR,
+                    (errcode(ERRCODE_UNDEFINED_TABLE),
+                     errmsg("Invalid number of attributes for %s.%s",
+                     ggctx->graph_name, vertex_label_name)));
+        }
+        /* get all tuples in table and insert them into graph hashtables */
+        while((tuple = heap_getnext(scan_desc, ForwardScanDirection)) != NULL)
+        {
+            graphid vertex_id;
+            Datum vertex_properties;
+            bool inserted = false;
+
+            /* something is wrong if this isn't true */
+            Assert(HeapTupleIsValid(tuple));
+            /* get the vertex id */
+            vertex_id = DatumGetInt64(column_get_datum(tupdesc, tuple, 0, "id",
+                                                       GRAPHIDOID, true));
+            /* get the vertex properties datum */
+            vertex_properties = column_get_datum(tupdesc, tuple, 1,
+                                                 "properties", AGTYPEOID, true);
+
+            /* insert vertex into vertex hashtable */
+            inserted = insert_vertex_entry(ggctx, vertex_id,
+                                           vertex_label_table_oid,
+                                           vertex_properties);
+            /* this insert must not fail */
+            if (!inserted)
+            {
+                 elog(ERROR, "insert_vertex_entry: failed to insert");
+            }
+        }
+
+        /* end the scan and close the relation */
+        heap_endscan(scan_desc);
+        heap_close(graph_vertex_label, ShareLock);
+    }
+}
+
+/*
+ * Helper function to load all of the GRAPH global hashtables (vertex & edge)
+ * for the current global context.
+ */
+static void load_GRAPH_global_hashtables(GRAPH_global_context *ggctx)
+{
+    /* initialize statistics */
+    ggctx->num_loaded_vertices = 0;
+    ggctx->num_loaded_edges = 0;
+
+    /* insert all of our vertices */
+    load_vertex_hashtable(ggctx);
+
+    /* insert all of our edges */
+    load_edge_hashtable(ggctx);
+}
+
+/*
+ * Helper routine to load all edges into the GRAPH global edge and vertex
+ * hashtables.
+ */
+static void load_edge_hashtable(GRAPH_global_context *ggctx)
+{
+    Oid graph_oid;
+    Oid graph_namespace_oid;
+    Snapshot snapshot;
+    List *edge_label_names = NIL;
+    ListCell *lc;
+
+    /* get the specific graph OID and namespace (schema) OID */
+    graph_oid = ggctx->graph_oid;
+    graph_namespace_oid = get_namespace_oid(ggctx->graph_name, false);
+    /* get the active snapshot */
+    snapshot = GetActiveSnapshot();
+    /* get the names of all of the edge label tables */
+    edge_label_names = get_ag_labels_names(snapshot, graph_oid,
+                                           LABEL_TYPE_EDGE);
+    /* go through all edge label tables in list */
+    foreach (lc, edge_label_names)
+    {
+        Relation graph_edge_label;
+        HeapScanDesc scan_desc;
+        HeapTuple tuple;
+        char *edge_label_name;
+        Oid edge_label_table_oid;
+        TupleDesc tupdesc;
+
+        /* get the edge label name */
+        edge_label_name = lfirst(lc);
+        /* get the edge label name's OID */
+        edge_label_table_oid = get_relname_relid(edge_label_name,
+                                                 graph_namespace_oid);
+        /* open the relation (table) and begin the scan */
+        graph_edge_label = heap_open(edge_label_table_oid, ShareLock);
+        scan_desc = heap_beginscan(graph_edge_label, snapshot, 0, NULL);
+        /* get the tupdesc - we don't need to release this one */
+        tupdesc = RelationGetDescr(graph_edge_label);
+        /* bail if the number of columns differs */
+        if (tupdesc->natts != 4)
+        {
+            ereport(ERROR,
+                    (errcode(ERRCODE_UNDEFINED_TABLE),
+                     errmsg("Invalid number of attributes for %s.%s",
+                     ggctx->graph_name, edge_label_name)));
+        }
+        /* get all tuples in table and insert them into graph hashtables */
+        while((tuple = heap_getnext(scan_desc, ForwardScanDirection)) != NULL)
+        {
+            graphid edge_id;
+            graphid edge_vertex_start_id;
+            graphid edge_vertex_end_id;
+            Datum edge_properties;
+            bool inserted = false;
+
+            /* something is wrong if this isn't true */
+            Assert(HeapTupleIsValid(tuple));
+            /* get the edge id */
+            edge_id = DatumGetInt64(column_get_datum(tupdesc, tuple, 0, "id",
+                                                     GRAPHIDOID, true));
+            /* get the edge start_id (start vertex id) */
+            edge_vertex_start_id = DatumGetInt64(column_get_datum(tupdesc,
+                                                                  tuple, 1,
+                                                                  "start_id",
+                                                                  GRAPHIDOID,
+                                                                  true));
+            /* get the edge end_id (end vertex id)*/
+            edge_vertex_end_id = DatumGetInt64(column_get_datum(tupdesc, tuple,
+                                                                2, "end_id",
+                                                                GRAPHIDOID,
+                                                                true));
+            /* get the edge properties datum */
+            edge_properties = column_get_datum(tupdesc, tuple, 3, "properties",
+                                               AGTYPEOID, true);
+
+            /* insert edge into edge hashtable */
+            inserted = insert_edge(ggctx, edge_id, edge_properties,
+                                   edge_vertex_start_id, edge_vertex_end_id,
+                                   edge_label_table_oid);
+            /* this insert must not fail */
+            if (!inserted)
+            {
+                 elog(ERROR, "insert_edge: failed to insert");
+            }
+
+            /* insert the edge into this vertex's edge list */
+            inserted = insert_vertex_edge(ggctx, edge_vertex_start_id,
+                                          edge_id);
+            /* this insert must not fail */
+            if (!inserted)
+            {
+                 elog(ERROR, "insert_vertex_edge: failed to insert");
+            }
+
+            /*
+             * Insert the edge into this vertex's edge list. UNLESS this is a
+             * self loop (start == end  vertex) because that would be adding it
+             * twice.
+             */
+            if (edge_vertex_start_id != edge_vertex_end_id)
+            {
+                inserted = insert_vertex_edge(ggctx, edge_vertex_end_id,
+                                              edge_id);
+                /* this insert much not fail */
+                if (!inserted)
+                {
+                     elog(ERROR, "insert_vertex_edge: failed to insert");
+                }
+            }
+        }
+
+        /* end the scan and close the relation */
+        heap_endscan(scan_desc);
+        heap_close(graph_edge_label, ShareLock);
+    }
+}
+
+/*
+ * Helper function to freeze the GRAPH global hashtables from additional
+ * inserts. This may, or may not, be useful. Currently, these hashtables are
+ * only seen by the creating process and only for reading.
+ */
+static void freeze_GRAPH_global_hashtables(GRAPH_global_context *ggctx)
+{
+    hash_freeze(ggctx->vertex_hashtable);
+    hash_freeze(ggctx->edge_hashtable);
+}
+
+/*
+ * Helper function to free the entire specified GRAPH global context. After
+ * running this you should not use the pointer in ggctx.
+ */
+static void free_specific_GRAPH_global_context(GRAPH_global_context *ggctx)
+{
+    GraphIdNode *curr_vertex = NULL;
+
+    /* don't do anything if NULL */
+    if (ggctx == NULL)
+    {
+        return;
+    }
+
+    /* free the graph name */
+    pfree(ggctx->graph_name);
+
+    /* free the vertex edge lists, starting with the head */
+    curr_vertex = peek_stack_head(ggctx->vertices);
+    while (curr_vertex != NULL)
+    {
+        GraphIdNode *next_vertex = NULL;
+        vertex_entry *value = NULL;
+        bool found = false;
+        graphid vertex_id;
+
+        /* get the next vertex in the list, if any */
+        next_vertex = next_GraphIdNode(curr_vertex);
+
+        /* get the current vertex id */
+        vertex_id = get_graphid(curr_vertex);
+
+        /* retrieve the vertex entry */
+        value = (vertex_entry *)hash_search(ggctx->vertex_hashtable,
+                                            (void *)&vertex_id, HASH_FIND,
+                                            &found);
+        /* this is bad if it isn't found */
+        Assert(found);
+
+        /* free the edge list associated with this vertex */
+        free_ListGraphId(value->edges);
+
+        /* move to the next vertex */
+        curr_vertex = next_vertex;
+    }
+
+    /* free the vertices list */
+    free_ListGraphId(ggctx->vertices);
+
+    /* free the hashtables */
+    hash_destroy(ggctx->vertex_hashtable);
+    hash_destroy(ggctx->edge_hashtable);
+
+    /* free the context */
+    pfree(ggctx);
+}
+
+/*
+ * Helper function to manage the GRAPH global contexts. It will create the
+ * context for the graph specified, provided it isn't already built and valid.
+ * During processing it will free (delete) all invalid GRAPH contexts. It
+ * returns the GRAPH global context for the specified graph.
+ */
+GRAPH_global_context *manage_GRAPH_global_contexts(char *graph_name,
+                                                   Oid graph_oid)
+{
+    GRAPH_global_context *new_ggctx = NULL;
+    GRAPH_global_context *curr_ggctx = NULL;
+    GRAPH_global_context *prev_ggctx = NULL;
+    MemoryContext oldctx = NULL;
+
+    /* we need a higher context, or one that isn't destroyed by SRF exit */
+    oldctx = MemoryContextSwitchTo(TopMemoryContext);
+
+    /*
+     * We need to see if any GRAPH global contexts already exist and if any do
+     * for this particular graph. There are 5 possibilities -
+     *
+     *     1) There are no global contexts.
+     *     2) One does exist for this graph but, is invalid.
+     *     3) One does exist for this graph and is valid.
+     *     4) One or more other contexts do exist and all are valid.
+     *     5) One or more other contexts do exist but, one or more are invalid.
+     */
+
+    /* free the invalidated GRAPH global contexts first */
+    prev_ggctx = NULL;
+    curr_ggctx = global_graph_contexts;
+    while (curr_ggctx != NULL)
+    {
+        GRAPH_global_context *next_ggctx = curr_ggctx->next;
+
+        /* if the transaction ids have changed, we have an invalid graph */
+        if (curr_ggctx->xmin != GetActiveSnapshot()->xmin ||
+            curr_ggctx->xmax != GetActiveSnapshot()->xmax)
+        {
+            /*
+             * If prev_ggctx is NULL then we are freeing the top of the
+             * contexts. So, we need to point the global variable to the
+             * new (next) top context, if there is one.
+             */
+            if (prev_ggctx == NULL)
+            {
+                global_graph_contexts = next_ggctx;
+            }
+            else
+            {
+                prev_ggctx->next = curr_ggctx->next;
+            }
+
+            /* free the current graph context */
+            free_specific_GRAPH_global_context(curr_ggctx);
+        }
+        else
+        {
+            prev_ggctx = curr_ggctx;
+        }
+
+        /* advance to the next context */
+        curr_ggctx = next_ggctx;
+    }
+
+    /* find our graph's context. if it exists, we are done */
+    curr_ggctx = global_graph_contexts;
+    while (curr_ggctx != NULL)
+    {
+        if (curr_ggctx->graph_oid == graph_oid)
+        {
+            /* switch our context back */
+            MemoryContextSwitchTo(oldctx);
+            /* we are done */
+            return curr_ggctx;
+        }
+        curr_ggctx = curr_ggctx->next;
+    }
+
+    /* otherwise, we need to create one and possibly attach it */
+    new_ggctx = palloc0(sizeof(GRAPH_global_context));
+
+    if (global_graph_contexts != NULL)
+    {
+        new_ggctx->next = global_graph_contexts;
+    }
+    else
+    {
+        new_ggctx->next = NULL;
+    }
+
+    /* set the global context variable */
+    global_graph_contexts = new_ggctx;
+
+    /* set the graph name and oid */
+    new_ggctx->graph_name = pstrdup(graph_name);
+    new_ggctx->graph_oid = graph_oid;
+
+    /* set the transaction ids */
+    new_ggctx->xmin = GetActiveSnapshot()->xmin;
+    new_ggctx->xmax = GetActiveSnapshot()->xmax;
+
+    /* initialize our vertices list */
+    new_ggctx->vertices = NULL;
+
+    /* build the hashtables for this graph */
+    create_GRAPH_global_hashtables(new_ggctx);
+    load_GRAPH_global_hashtables(new_ggctx);
+    freeze_GRAPH_global_hashtables(new_ggctx);
+
+    /* switch back to the previous memory context */
+    MemoryContextSwitchTo(oldctx);
+
+    return new_ggctx;
+}
+
+/*
+ * Helper function to retrieve a vertex_entry from the graph's vertex hash
+ * table. If there isn't one, it returns a NULL. The latter is necessary for
+ * checking if the vsid and veid entries exist.
+ */
+vertex_entry *get_vertex_entry(GRAPH_global_context *ggctx, graphid vertex_id)
+{
+    vertex_entry *ve = NULL;
+    bool found = false;
+
+    /* retrieve the current vertex entry */
+    ve = (vertex_entry *)hash_search(ggctx->vertex_hashtable,
+                                     (void *)&vertex_id, HASH_FIND, &found);
+    return ve;
+}
+
+/* helper function to retrieve an edge_entry from the graph's edge hash table */
+edge_entry *get_edge_entry(GRAPH_global_context *ggctx, graphid edge_id)
+{
+    edge_entry *ee = NULL;
+    bool found = false;
+
+    /* retrieve the current edge entry */
+    ee = (edge_entry *)hash_search(ggctx->edge_hashtable, (void *)&edge_id,
+                                   HASH_FIND, &found);
+    /* it should be found, otherwise we have problems */
+    Assert(found);
+
+    return ee;
+}
+
+/*
+ * Helper function to find the GRAPH_global_context used by the specified
+ * graph_oid. If not found, it returns NULL.
+ */
+GRAPH_global_context *find_GRAPH_global_context(Oid graph_oid)
+{
+    GRAPH_global_context *ggctx = NULL;
+
+    /* get the root */
+    ggctx = global_graph_contexts;
+
+    while(ggctx != NULL)
+    {
+        /* if we found it return it */
+        if (ggctx->graph_oid == graph_oid)
+        {
+            return ggctx;
+        }
+
+        /* advance to the next context */
+        ggctx = ggctx->next;
+    }
+
+    /* we did not find it so return NULL */
+    return NULL;
+}
+
+/* graph vertices accessor */
+inline ListGraphId *get_graph_vertices(GRAPH_global_context *ggctx)
+{
+    return ggctx->vertices;
+}
+
+/* vertex_entry accessor functions */
+inline graphid get_vertex_entry_id(vertex_entry *ve)
+{
+    return ve->vertex_id;
+}
+
+inline ListGraphId *get_vertex_entry_edges(vertex_entry *ve)
+{
+    return ve->edges;
+}
+
+inline Oid get_vertex_entry_label_table_oid(vertex_entry *ve)
+{
+    return ve->vertex_label_table_oid;
+}
+
+inline Datum get_vertex_entry_properties(vertex_entry *ve)
+{
+    return ve->vertex_properties;
+}
+
+/* edge_entry accessor functions */
+inline graphid get_edge_entry_id(edge_entry *ee)
+{
+    return ee->edge_id;
+}
+
+inline Oid get_edge_entry_label_table_oid(edge_entry *ee)
+{
+    return ee->edge_label_table_oid;
+}
+
+inline Datum get_edge_entry_properties(edge_entry *ee)
+{
+    return ee->edge_properties;
+}
+
+inline graphid get_edge_entry_start_vertex_id(edge_entry *ee)
+{
+    return ee->start_vertex_id;
+}
+
+inline graphid get_edge_entry_end_vertex_id(edge_entry *ee)
+{
+    return ee->end_vertex_id;
+}
diff --git a/src/backend/utils/adt/age_graphid_ds.c b/src/backend/utils/adt/age_graphid_ds.c
new file mode 100644
index 0000000..d5c46c5
--- /dev/null
+++ b/src/backend/utils/adt/age_graphid_ds.c
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "postgres.h"
+
+#include "utils/graphid.h"
+#include "utils/age_graphid_ds.h"
+
+/* defines */
+/*
+ * A simple linked list node for graphid lists (int64). PG's implementation
+ * has too much overhead for this type of list as it only directly supports
+ * regular ints, not int64s, of which a graphid currently is.
+ */
+typedef struct GraphIdNode
+{
+    graphid id;
+    struct GraphIdNode *next;
+} GraphIdNode;
+
+/* a container for a linked list of GraphIdNodes */
+typedef struct ListGraphId
+{
+    GraphIdNode *head;
+    GraphIdNode *tail;
+    int64 size;
+} ListGraphId;
+
+/* declarations */
+
+/* definitions */
+/* return the next GraphIdNode */
+inline GraphIdNode *next_GraphIdNode(GraphIdNode *node)
+{
+    return node->next;
+}
+
+/* return the graphid */
+inline graphid get_graphid(GraphIdNode *node)
+{
+    return node->id;
+}
+
+/* get the size of the passed stack */
+inline int64 get_stack_size(ListGraphId *stack)
+{
+    return stack->size;
+}
+
+/* return a reference to the head entry in the stack */
+inline GraphIdNode *peek_stack_head(ListGraphId *stack)
+{
+    return stack->head;
+}
+
+/* return a reference to the tail entry in the stack */
+inline GraphIdNode *peek_stack_tail(ListGraphId *stack)
+{
+    return stack->tail;
+}
+
+/*
+ * Helper function to add a graphid to the end of a ListGraphId container.
+ * If the container is NULL, it creates the container with the entry.
+ */
+ListGraphId *append_graphid(ListGraphId *container, graphid id)
+{
+    GraphIdNode *new_node = NULL;
+
+    /* create the new link */
+    new_node = palloc0(sizeof(GraphIdNode));
+    new_node->id = id;
+    new_node->next = NULL;
+
+    /*
+     * If the container is NULL then this is a new list. So, create the
+     * container and add in the new link.
+     */
+    if (container == NULL)
+    {
+        container = palloc0(sizeof(ListGraphId));
+        container->head = new_node;
+        container->tail = new_node;
+        container->size = 1;
+    }
+    /* otherwise, this is an existing list, append id */
+    else
+    {
+        container->tail->next = new_node;
+        container->tail = new_node;
+        container->size++;
+    }
+
+    return container;
+}
+
+/* free (delete) a ListGraphId list */
+void free_ListGraphId(ListGraphId *container)
+{
+    GraphIdNode *curr_node = NULL;
+    GraphIdNode *next_node = NULL;
+
+    /* if the container is NULL we don't need to delete anything */
+    if (container == NULL)
+    {
+        return;
+    }
+
+    /* otherwise, start from the head, free, and delete the links */
+    curr_node = container->head;
+    while (curr_node != NULL)
+    {
+        next_node = curr_node->next;
+        /* we can do this because this is just a list of ints */
+        pfree(curr_node);
+        curr_node = next_node;
+    }
+
+    /* free the container */
+    pfree(container);
+}
+
+/* helper function to create a new, empty, graphid stack */
+ListGraphId *new_graphid_stack(void)
+{
+    ListGraphId *stack = NULL;
+
+    /* allocate the container for the stack */
+    stack = palloc0(sizeof(ListGraphId));
+
+    /* set it to its initial values */
+    stack->head = NULL;
+    stack->tail = NULL;
+    stack->size = 0;
+
+    /* return the new stack */
+    return stack;
+}
+
+/* helper function to free a graphid stack's contents but, not the container */
+void free_graphid_stack(ListGraphId *stack)
+{
+    Assert(stack != NULL);
+
+    if (stack == NULL)
+    {
+        elog(ERROR, "free_graphid_stack: NULL stack");
+    }
+
+    /* while there are entries */
+    while (stack->head != NULL)
+    {
+        /* get the next element in the stack */
+        GraphIdNode *next = stack->head->next;
+
+        /* free the head element */
+        pfree(stack->head);
+        /* move the head to the next */
+        stack->head = next;
+    }
+
+    /* reset the tail and size */
+    stack->tail = NULL;
+    stack->size = 0;
+}
+
+/*
+ * Helper function for a generic push graphid (int64) to a stack. If the stack
+ * is NULL, it will error out.
+ */
+void push_graphid_stack(ListGraphId *stack, graphid id)
+{
+    GraphIdNode *new_node = NULL;
+
+    Assert(stack != NULL);
+
+    if (stack == NULL)
+    {
+        elog(ERROR, "push_graphid_stack: NULL stack");
+    }
+
+    /* create the new element */
+    new_node = palloc0(sizeof(GraphIdNode));
+    new_node->id = id;
+
+    /* insert (push) the new element on the top */
+    new_node->next = stack->head;
+    stack->head = new_node;
+    stack->size++;
+}
+
+/*
+ * Helper function for a generic pop graphid (int64) from a stack. If the stack
+ * is empty, it will error out. You should verify that the stack isn't empty
+ * prior to calling.
+ */
+graphid pop_graphid_stack(ListGraphId *stack)
+{
+    GraphIdNode *node = NULL;
+    graphid id;
+
+    Assert(stack != NULL);
+    Assert(stack->size != 0);
+
+    if (stack == NULL)
+    {
+        elog(ERROR, "pop_graphid_stack: NULL stack");
+    }
+
+    if (stack->size <= 0)
+    {
+        elog(ERROR, "pop_graphid_stack: empty stack");
+    }
+
+
+    /* remove the element from the top of the stack */
+    node = stack->head;
+    id = node->id;
+    stack->head = stack->head->next;
+    stack->size--;
+    /* free the element */
+    pfree(node);
+
+    /* return the id */
+    return id;
+}
diff --git a/src/backend/utils/adt/agtype_vle.c b/src/backend/utils/adt/age_vle.c
similarity index 65%
rename from src/backend/utils/adt/agtype_vle.c
rename to src/backend/utils/adt/age_vle.c
index 1f17f1a..9d839dc 100644
--- a/src/backend/utils/adt/agtype_vle.c
+++ b/src/backend/utils/adt/age_vle.c
@@ -19,71 +19,23 @@
 
 #include "postgres.h"
 
-#include "catalog/namespace.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
-#include "utils/datum.h"
 #include "utils/lsyscache.h"
-#include "utils/rel.h"
-#include "utils/snapmgr.h"
 
-#include "commands/label_commands.h"
-#include "utils/agtype.h"
-#include "utils/agtype_vle.h"
+#include "utils/age_vle.h"
 #include "catalog/ag_graph.h"
-#include "catalog/ag_label.h"
 #include "utils/graphid.h"
+#include "utils/age_graphid_ds.h"
 #include "nodes/cypher_nodes.h"
 
 /* defines */
-#define VERTEX_HTAB_NAME "Vertex to edge lists " /* added a space at end for */
-#define EDGE_HTAB_NAME "Edge to vertex mapping " /* the graph name to follow */
-#define EDGE_STATE_HTAB_NAME "Edge state "
-
 #define GET_GRAPHID_ARRAY_FROM_CONTAINER(vpc) \
             (graphid *) (&vpc->graphid_array_data)
-#define IS_STACK_EMPTY(stack) \
-            (ListGraphId *)stack->size == 0
-#define PEEK_STACK(stack) \
-            (graphid) (ListGraphId *)stack->head->id
-/*
- * A simple linked list node for graphid lists (int64). PG's implementation
- * has too much overhead for this type of list as it only directly supports
- * regular ints, not int64s, of which a graphid currently is.
- */
-typedef struct GraphIdNode
-{
-    graphid id;
-    struct GraphIdNode *next;
-} GraphIdNode;
-
-/* a container for a linked list of GraphIdNodes */
-typedef struct ListGraphId
-{
-    GraphIdNode *head;
-    GraphIdNode *tail;
-    int64 size;
-} ListGraphId;
-
-/* vertex entry for the vertex_hastable */
-typedef struct vertex_entry
-{
-    graphid vertex_id;             /* vertex id, it is also the hash key */
-    ListGraphId *edges;            /* A list of all (entering & exiting) edges'
-                                    * graphids (int64s). */
-    Oid vertex_label_table_oid;    /* the label table oid */
-    Datum vertex_properties;       /* datum property value */
-} vertex_entry;
-
-/* edge entry for the edge_hashtable */
-typedef struct edge_entry
-{
-    graphid edge_id;               /* edge id, it is also the hash key */
-    Oid edge_label_table_oid;      /* the label table oid */
-    Datum edge_properties;         /* datum property value */
-    graphid start_vertex_id;       /* start vertex */
-    graphid end_vertex_id;         /* end vertex */
-} edge_entry;
+#define EDGE_STATE_HTAB_NAME "Edge state "
+#define EDGE_STATE_HTAB_INITIAL_SIZE 100000
+#define EXISTS_HTAB_NAME "known edges"
+#define EXISTS_HTAB_NAME_INITIAL_SIZE 1000
 
 /* edge state entry for the edge_state_hashtable */
 typedef struct edge_state_entry
@@ -95,25 +47,6 @@ typedef struct edge_state_entry
 } edge_state_entry;
 
 /*
- * VLE global context per graph. They are chained together via next.
- * Be aware that the global pointer will point to the root BUT that
- * the root will change as new graphs are added to the top.
- */
-typedef struct VLE_global_context
-{
-    char *graph_name;              /* graph name */
-    Oid graph_oid;                 /* graph oid for searching */
-    HTAB *vertex_hashtable;        /* hashtable to hold vertex edge lists */
-    HTAB *edge_hashtable;          /* hashtable to hold edge to vertex map */
-    TransactionId xmin;            /* transaction ids for this graph */
-    TransactionId xmax;
-    int64 num_loaded_vertices;     /* number of loaded vertices in this graph */
-    int64 num_loaded_edges;        /* number of loaded edges in this graph */
-    ListGraphId *vertices;         /* vertices for vertex hashtable cleanup */
-    struct VLE_global_context *next; /* next graph */
-} VLE_global_context;
-
-/*
  * VLE_path_function is an enum for the path function to use. This currently can
  * be one of two possibilities - where the target vertex is provided and where
  * it isn't.
@@ -133,7 +66,7 @@ typedef struct VLE_local_context
 {
     char *graph_name;              /* name of the graph */
     Oid graph_oid;                 /* graph oid for searching */
-    VLE_global_context *vlegctx;   /* global context for this local context */
+    GRAPH_global_context *ggctx;   /* global graph context pointer */
     graphid vsid;                  /* starting vertex id */
     graphid veid;                  /* ending vertex id */
     char *edge_label_name;         /* edge label name for match */
@@ -142,8 +75,6 @@ typedef struct VLE_local_context
     int64 uidx;                    /* upper (end) bound index */
     bool uidx_infinite;            /* flag if the upper bound is omitted */
     cypher_rel_dir edge_direction; /* the direction of the edge */
-    HTAB *vertex_hashtable;        /* link to this context vertex hashtable */
-    HTAB *edge_hashtable;          /* link to this context edge hashtable */
     HTAB *edge_state_hashtable;    /* local state hashtable for our edges */
     ListGraphId *dfs_vertex_stack; /* dfs stack for vertices */
     ListGraphId *dfs_edge_stack;   /* dfs stack for edges */
@@ -168,9 +99,6 @@ typedef struct VLE_path_container
     graphid graphid_array_data;
 } VLE_path_container;
 
-/* global variable to hold the per process VLE global context */
-static VLE_global_context *global_vle_contexts = NULL;
-
 /* declarations */
 /* agtype functions */
 static agtype_value *get_agtype_key(agtype_value *agtv, char *search_key,
@@ -180,43 +108,14 @@ static agtype_iterator *get_next_object_pair(agtype_iterator *it,
                                              agtype_value *key,
                                              agtype_value *value);
 static bool is_an_edge_match(VLE_local_context *vlelctx, edge_entry *ee);
-/* VLE global context functions */
-static VLE_global_context *manage_VLE_global_contexts(char *graph_name,
-                                                      Oid graph_oid);
-static void free_specific_global_context(VLE_global_context *vlegctx);
-static void create_VLE_global_hashtables(VLE_global_context *vlegctx);
-static void load_VLE_global_hashtables(VLE_global_context *vlegctx);
-static void load_vertex_hashtable(VLE_global_context *vlegctx);
-static void load_edge_hashtable(VLE_global_context *vlegctx);
-static void freeze_VLE_global_hashtables(VLE_global_context *vlegctx);
-static List *get_ag_labels_names(Snapshot snapshot, Oid graph_oid,
-                                 char label_type);
-static bool insert_edge(VLE_global_context *vlegctx, graphid edge_id,
-                        Datum edge_properties, graphid start_vertex_id,
-                        graphid end_vertex_id, Oid edge_label_table_oid);
-static bool insert_vertex_edge(VLE_global_context *vlegctx, graphid vertex_id,
-                          graphid edge_id);
-static bool insert_vertex_entry(VLE_global_context *vlegctx, graphid vertex_id,
-                                Oid vertex_label_table_oid,
-                                Datum vertex_properties);
-static VLE_global_context *find_VLE_global_context(Oid graph_oid);
 /* VLE local context functions */
 static VLE_local_context *build_local_vle_context(FunctionCallInfo fcinfo);
 static void create_VLE_local_state_hashtable(VLE_local_context *vlelctx);
 static void free_VLE_local_context(VLE_local_context *vlelctx);
-/* graphid list functions */
-static ListGraphId *append_graphid(ListGraphId *container, graphid id);
-static void free_ListGraphId(ListGraphId *container);
 /* VLE graph traversal functions */
-static vertex_entry *get_vertex_entry(VLE_local_context *vlelctx,
-                                      graphid vertex_id);
-static edge_entry *get_edge_entry(VLE_local_context *vlelctx, graphid edge_id);
 static edge_state_entry *get_edge_state(VLE_local_context *vlelctx,
                                         graphid edge_id);
-static ListGraphId *new_stack(void);
-static void free_stack(ListGraphId *stack);
-static void push_stack(ListGraphId *stack, graphid id);
-static graphid pop_stack(ListGraphId *stack);
+/* graphid data structures */
 static void load_initial_dfs_stacks(VLE_local_context *vlelctx);
 static bool dfs_find_a_path_between(VLE_local_context *vlelctx);
 static bool dfs_find_a_path_from(VLE_local_context *vlelctx);
@@ -233,118 +132,6 @@ static agtype_value *build_path(VLE_path_container *vpc);
 static agtype_value *build_edge_list(VLE_path_container *vpc);
 
 /* definitions */
-/*
- * Helper function to add a graphid to the end of a ListGraphId container.
- * If the container is NULL, it creates the container with the entry.
- */
-static ListGraphId *append_graphid(ListGraphId *container, graphid id)
-{
-    GraphIdNode *new_node = NULL;
-
-    /* create the new link */
-    new_node = palloc0(sizeof(GraphIdNode));
-    new_node->id = id;
-    new_node->next = NULL;
-
-    /*
-     * If the container is NULL then this is a new list. So, create the
-     * container and add in the new link.
-     */
-    if (container == NULL)
-    {
-        container = palloc0(sizeof(ListGraphId));
-        container->head = new_node;
-        container->tail = new_node;
-        container->size = 1;
-    }
-    /* otherwise, this is an existing list, append id */
-    else
-    {
-        container->tail->next = new_node;
-        container->tail = new_node;
-        container->size++;
-    }
-
-    return container;
-}
-
-/* free (delete) a ListGraphId list */
-static void free_ListGraphId(ListGraphId *container)
-{
-    GraphIdNode *curr_node = NULL;
-    GraphIdNode *next_node = NULL;
-
-    /* if the container is NULL we don't need to delete anything */
-    if (container == NULL)
-    {
-        return;
-    }
-
-    /* otherwise, start from the head, free, and delete the links */
-    curr_node = container->head;
-    while (curr_node != NULL)
-    {
-        next_node = curr_node->next;
-        /* we can do this because this is just a list of ints */
-        pfree(curr_node);
-        curr_node = next_node;
-    }
-
-    /* free the container */
-    pfree(container);
-}
-
-/*
- * Helper function to create the global VLE vertex and edge hashtables. One
- * hashtable will hold the vertex and its edges (both incoming and exiting), as
- * a list. The other hashtable will hold the edge, its properties datum, and its
- * target vertex.
- */
-static void create_VLE_global_hashtables(VLE_global_context *vlegctx)
-{
-    HASHCTL vertex_ctl;
-    HASHCTL edge_ctl;
-    char *graph_name = NULL;
-    char *vhn = NULL;
-    char *ehn = NULL;
-    int glen;
-    int vlen;
-    int elen;
-
-    /* get the graph name and length */
-    graph_name = vlegctx->graph_name;
-    glen = strlen(graph_name);
-    /* get the vertex htab name length */
-    vlen = strlen(VERTEX_HTAB_NAME);
-    /* get the edge htab name length */
-    elen = strlen(EDGE_HTAB_NAME);
-    /* allocate the space and build the names */
-    vhn = palloc0(vlen + glen + 1);
-    ehn = palloc0(elen + glen + 1);
-    /* copy in the names */
-    strcpy(vhn, VERTEX_HTAB_NAME);
-    strcpy(ehn, EDGE_HTAB_NAME);
-    /* add in the graph name */
-    vhn = strncat(vhn, graph_name, glen);
-    ehn = strncat(ehn, graph_name, glen);
-
-    /* initialize the vertex hashtable */
-    MemSet(&vertex_ctl, 0, sizeof(vertex_ctl));
-    vertex_ctl.keysize = sizeof(int64);
-    vertex_ctl.entrysize = sizeof(vertex_entry);
-    vertex_ctl.hash = tag_hash;
-    vlegctx->vertex_hashtable = hash_create(vhn, 1000000, &vertex_ctl,
-                                            HASH_ELEM | HASH_FUNCTION);
-
-    /* initialize the edge hashtable */
-    MemSet(&edge_ctl, 0, sizeof(edge_ctl));
-    edge_ctl.keysize = sizeof(int64);
-    edge_ctl.entrysize = sizeof(edge_entry);
-    edge_ctl.hash = tag_hash;
-    vlegctx->edge_hashtable = hash_create(ehn, 1000000, &edge_ctl,
-                                          HASH_ELEM | HASH_FUNCTION);
-}
-
 /* helper function to create the local VLE edge state hashtable. */
 static void create_VLE_local_state_hashtable(VLE_local_context *vlelctx)
 {
@@ -358,7 +145,7 @@ static void create_VLE_local_state_hashtable(VLE_local_context *vlelctx)
     graph_name = vlelctx->graph_name;
     glen = strlen(graph_name);
     /* get the edge state htab name length */
-    elen = strlen(EDGE_HTAB_NAME);
+    elen = strlen(EDGE_STATE_HTAB_NAME);
     /* allocate the space and build the name */
     eshn = palloc0(elen + glen + 1);
     /* copy in the name */
@@ -371,7 +158,9 @@ static void create_VLE_local_state_hashtable(VLE_local_context *vlelctx)
     edge_state_ctl.keysize = sizeof(int64);
     edge_state_ctl.entrysize = sizeof(edge_state_entry);
     edge_state_ctl.hash = tag_hash;
-    vlelctx->edge_state_hashtable = hash_create(eshn, 100000, &edge_state_ctl,
+    vlelctx->edge_state_hashtable = hash_create(eshn,
+                                                EDGE_STATE_HTAB_INITIAL_SIZE,
+                                                &edge_state_ctl,
                                                 HASH_ELEM | HASH_FUNCTION);
 }
 
@@ -431,7 +220,8 @@ static agtype_iterator *get_next_object_pair(agtype_iterator *it,
 
     /*
      * The next token should be a value but, it could be a begin tokens for
-     * arrays or objects. For those we just return NULL to ignore them.
+     * arrays or objects. For those we don't want to step into them, just leave
+     * them as is.
      */
     itok = agtype_iterator_next(&it, &tmp, true);
     Assert(itok == WAGT_VALUE);
@@ -481,9 +271,9 @@ static bool is_an_edge_match(VLE_local_context *vlelctx, edge_entry *ee)
     }
 
     /* get the edge label name from the oid */
-    edge_label_name = get_rel_name(ee->edge_label_table_oid);
+    edge_label_name = get_rel_name(get_edge_entry_label_table_oid(ee));
     /* get our edge's properties */
-    agt_edge_properties = DATUM_GET_AGTYPE_P(ee->edge_properties);
+    agt_edge_properties = DATUM_GET_AGTYPE_P(get_edge_entry_properties(ee));
     /* get the container */
     agtc_edge_properties = &agt_edge_properties->root;
     /* get the number of properties in the edge to be matched */
@@ -600,7 +390,6 @@ static bool is_an_edge_match(VLE_local_context *vlelctx, edge_entry *ee)
 /*
  * Helper function to iterate through all object pairs, looking for a specific
  * key. It will return the key or NULL if not found.
- * TODO: what if the value is supposed to be NULL?
  */
 static agtype_value *get_agtype_key(agtype_value *agtv, char *search_key,
                                     int search_key_len)
@@ -608,7 +397,9 @@ static agtype_value *get_agtype_key(agtype_value *agtv, char *search_key,
     int i = 0;
 
     if (agtv == NULL || search_key == NULL || search_key_len <= 0)
+    {
         return NULL;
+    }
 
     /* iterate through all pairs */
     for (i = 0; i < agtv->val.object.num_pairs; i++)
@@ -624,169 +415,14 @@ static agtype_value *get_agtype_key(agtype_value *agtv, char *search_key,
         /* check for an id of type integer */
         if (current_key_len == search_key_len &&
             pg_strcasecmp(current_key, search_key) == 0)
+        {
             return agtv_value;
+        }
     }
 
     return NULL;
 }
 
-/* helper function to get a List of all label names for the specified graph */
-static List *get_ag_labels_names(Snapshot snapshot, Oid graph_oid,
-                                 char label_type)
-{
-    List *labels = NIL;
-    ScanKeyData scan_keys[2];
-    Relation ag_label;
-    HeapScanDesc scan_desc;
-    HeapTuple tuple;
-    TupleDesc tupdesc;
-
-    /* we need a valid snapshot */
-    Assert(snapshot != NULL);
-
-    /* setup scan keys to get all edges for the given graph oid */
-    ScanKeyInit(&scan_keys[1], Anum_ag_label_graph, BTEqualStrategyNumber,
-                F_OIDEQ, ObjectIdGetDatum(graph_oid));
-    ScanKeyInit(&scan_keys[0], Anum_ag_label_kind, BTEqualStrategyNumber,
-                F_CHAREQ, CharGetDatum(label_type));
-
-    /* setup the table to be scanned, ag_label in this case */
-    ag_label = heap_open(ag_label_relation_id(), ShareLock);
-    scan_desc = heap_beginscan(ag_label, snapshot, 2, scan_keys);
-
-    /* get the tupdesc - we don't need to release this one */
-    tupdesc = RelationGetDescr(ag_label);
-    /* bail if the number of columns differs - this table has 5 */
-    Assert(tupdesc->natts == 5);
-
-    /* get all of the label names */
-    while((tuple = heap_getnext(scan_desc, ForwardScanDirection)) != NULL)
-    {
-        Name label;
-
-        /* something is wrong if this tuple isn't valid */
-        Assert(HeapTupleIsValid(tuple));
-        /* get the label name */
-        label = DatumGetName(column_get_datum(tupdesc, tuple, 0, "name",
-                                              NAMEOID, true));
-        /* add it to our list */
-        labels = lappend(labels, label);
-    }
-
-    /* close up scan */
-    heap_endscan(scan_desc);
-    heap_close(ag_label, ShareLock);
-
-    return labels;
-}
-
-/*
- * Helper function to insert one edge/edge->vertex, key/value pair, in the
- * current global edge hashtable.
- */
-static bool insert_edge(VLE_global_context *vlegctx, graphid edge_id,
-                        Datum edge_properties, graphid start_vertex_id,
-                        graphid end_vertex_id, Oid edge_label_table_oid)
-{
-    edge_entry *value = NULL;
-    bool found = false;
-
-    /* search for the edge */
-    value = (edge_entry *)hash_search(vlegctx->edge_hashtable, (void *)&edge_id,
-                                      HASH_ENTER, &found);
-    /*
-     * If we found the key, either we have a duplicate, or we made a mistake and
-     * inserted it already. Either way, this isn't good so don't insert it and
-     * return false. Likewise, if the value returned is NULL, don't do anything,
-     * just return false. This way the caller can decide what to do.
-     */
-    if (found || value == NULL)
-    {
-        return false;
-    }
-
-    /* not sure if we really need to zero out the entry, as we set everything */
-    MemSet(value, 0, sizeof(edge_entry));
-
-    /*
-     * Set the edge id - this is important as this is the hash key value used
-     * for hash function collisions.
-     */
-    value->edge_id = edge_id;
-    value->edge_properties = edge_properties;
-    value->start_vertex_id = start_vertex_id;
-    value->end_vertex_id = end_vertex_id;
-    value->edge_label_table_oid = edge_label_table_oid;
-
-    /* increment the number of loaded edges */
-    vlegctx->num_loaded_edges++;
-
-    return true;
-}
-
-/*
- * Helper function to insert an entire vertex into the current global vertex
- * hashtable.
- */
-static bool insert_vertex_entry(VLE_global_context *vlegctx, graphid vertex_id,
-                                Oid vertex_label_table_oid,
-                                Datum vertex_properties)
-{
-    vertex_entry *ve = NULL;
-    bool found = false;
-
-    /* search for the vertex */
-    ve = (vertex_entry *)hash_search(vlegctx->vertex_hashtable,
-                                     (void *)&vertex_id, HASH_ENTER, &found);
-    /* we should never have duplicates */
-    Assert(!found);
-
-    /* again, MemSet may not be needed here */
-    MemSet(ve, 0, sizeof(vertex_entry));
-
-    /*
-     * Set the vertex id - this is important as this is the hash key value
-     * used for hash function collisions.
-     */
-    ve->vertex_id = vertex_id;
-    /* set the label table oid for this vertex */
-    ve->vertex_label_table_oid = vertex_label_table_oid;
-    /* set the datum vertex properties */
-    ve->vertex_properties = vertex_properties;
-    /* set the NIL edge list */
-    ve->edges = NULL;
-
-    /* we also need to store the vertex id for clean up of vertex lists */
-    vlegctx->vertices = append_graphid(vlegctx->vertices, vertex_id);
-
-    /* increment the number of loaded vertices */
-    vlegctx->num_loaded_vertices++;
-
-    return true;
-}
-
-/*
- * Helper function to append one edge to an existing vertex in the current
- * global vertex hashtable.
- */
-static bool insert_vertex_edge(VLE_global_context *vlegctx, graphid vertex_id,
-                               graphid edge_id)
-{
-    vertex_entry *value = NULL;
-    bool found = false;
-
-    /* search for the vertex */
-    value = (vertex_entry *)hash_search(vlegctx->vertex_hashtable,
-                                        (void *)&vertex_id, HASH_FIND, &found);
-    /* vertices were preloaded so it must be there */
-    Assert(found);
-
-    /* add the edge to the edge list */
-    value->edges = append_graphid(value->edges, edge_id);
-
-    return true;
-}
-
 /*
  * Helper function to free up the memory used by the VLE_local_context.
  *
@@ -808,9 +444,9 @@ static void free_VLE_local_context(VLE_local_context *vlelctx)
     vlelctx->edge_state_hashtable = NULL;
 
     /* we need to free our stacks */
-    free_stack(vlelctx->dfs_vertex_stack);
-    free_stack(vlelctx->dfs_edge_stack);
-    free_stack(vlelctx->dfs_path_stack);
+    free_graphid_stack(vlelctx->dfs_vertex_stack);
+    free_graphid_stack(vlelctx->dfs_edge_stack);
+    free_graphid_stack(vlelctx->dfs_path_stack);
     pfree(vlelctx->dfs_vertex_stack);
     pfree(vlelctx->dfs_edge_stack);
     pfree(vlelctx->dfs_path_stack);
@@ -822,397 +458,6 @@ static void free_VLE_local_context(VLE_local_context *vlelctx)
     pfree(vlelctx);
 }
 
-/* helper routine to load all vertices into the vertex hashtable */
-static void load_vertex_hashtable(VLE_global_context *vlegctx)
-{
-    Oid graph_oid;
-    Oid graph_namespace_oid;
-    Snapshot snapshot;
-    List *vertex_label_names = NIL;
-    ListCell *lc;
-
-    /* get the specific graph OID and namespace (schema) OID */
-    graph_oid = vlegctx->graph_oid;
-    graph_namespace_oid = get_namespace_oid(vlegctx->graph_name, false);
-    /* get the active snapshot */
-    snapshot = GetActiveSnapshot();
-    /* get the names of all of the vertex label tables */
-    vertex_label_names = get_ag_labels_names(snapshot, graph_oid,
-                                             LABEL_TYPE_VERTEX);
-    /* go through all vertex label tables in list */
-    foreach (lc, vertex_label_names)
-    {
-        Relation graph_vertex_label;
-        HeapScanDesc scan_desc;
-        HeapTuple tuple;
-        char *vertex_label_name;
-        Oid vertex_label_table_oid;
-        TupleDesc tupdesc;
-
-        /* get the vertex label name */
-        vertex_label_name = lfirst(lc);
-        /* get the vertex label name's OID */
-        vertex_label_table_oid = get_relname_relid(vertex_label_name,
-                                                   graph_namespace_oid);
-        /* open the relation (table) and begin the scan */
-        graph_vertex_label = heap_open(vertex_label_table_oid, ShareLock);
-        scan_desc = heap_beginscan(graph_vertex_label, snapshot, 0, NULL);
-        /* get the tupdesc - we don't need to release this one */
-        tupdesc = RelationGetDescr(graph_vertex_label);
-        /* bail if the number of columns differs */
-        if (tupdesc->natts != 2)
-            ereport(ERROR,
-                    (errcode(ERRCODE_UNDEFINED_TABLE),
-                     errmsg("Invalid number of attributes for %s.%s",
-                     vlegctx->graph_name, vertex_label_name)));
-        /* get all tuples in table and insert them into graph hashtables */
-        while((tuple = heap_getnext(scan_desc, ForwardScanDirection)) != NULL)
-        {
-            graphid vertex_id;
-            Datum vertex_properties;
-            bool inserted = false;
-
-            /* something is wrong if this isn't true */
-            Assert(HeapTupleIsValid(tuple));
-            /* get the vertex id */
-            vertex_id = DatumGetInt64(column_get_datum(tupdesc, tuple, 0, "id",
-                                                       GRAPHIDOID, true));
-            /* get the vertex properties datum */
-            vertex_properties = column_get_datum(tupdesc, tuple, 1,
-                                                 "properties", AGTYPEOID, true);
-
-            /* insert vertex into vertex hashtable */
-            inserted = insert_vertex_entry(vlegctx, vertex_id,
-                                           vertex_label_table_oid,
-                                           vertex_properties);
-            /* this insert must not fail */
-            if (!inserted)
-            {
-                 elog(ERROR, "insert_vertex_entry: failed to insert");
-            }
-        }
-
-        /* end the scan and close the relation */
-        heap_endscan(scan_desc);
-        heap_close(graph_vertex_label, ShareLock);
-    }
-}
-
-/*
- * Helper function to load all of the VLE hashtables (vertex & edge) for the
- * current global context (graph).
- */
-static void load_VLE_global_hashtables(VLE_global_context *vlegctx)
-{
-    /* initialize statistics */
-    vlegctx->num_loaded_vertices = 0;
-    vlegctx->num_loaded_edges = 0;
-
-    /* insert all of our vertices */
-    load_vertex_hashtable(vlegctx);
-
-    /* insert all of our edges */
-    load_edge_hashtable(vlegctx);
-}
-
-/* helper routine to load all edges into the edge and vertex hashtables */
-static void load_edge_hashtable(VLE_global_context *vlegctx)
-{
-    Oid graph_oid;
-    Oid graph_namespace_oid;
-    Snapshot snapshot;
-    List *edge_label_names = NIL;
-    ListCell *lc;
-
-    /* get the specific graph OID and namespace (schema) OID */
-    graph_oid = vlegctx->graph_oid;
-    graph_namespace_oid = get_namespace_oid(vlegctx->graph_name, false);
-    /* get the active snapshot */
-    snapshot = GetActiveSnapshot();
-    /* get the names of all of the edge label tables */
-    edge_label_names = get_ag_labels_names(snapshot, graph_oid,
-                                           LABEL_TYPE_EDGE);
-    /* go through all edge label tables in list */
-    foreach (lc, edge_label_names)
-    {
-        Relation graph_edge_label;
-        HeapScanDesc scan_desc;
-        HeapTuple tuple;
-        char *edge_label_name;
-        Oid edge_label_table_oid;
-        TupleDesc tupdesc;
-
-        /* get the edge label name */
-        edge_label_name = lfirst(lc);
-        /* get the edge label name's OID */
-        edge_label_table_oid = get_relname_relid(edge_label_name,
-                                                 graph_namespace_oid);
-        /* open the relation (table) and begin the scan */
-        graph_edge_label = heap_open(edge_label_table_oid, ShareLock);
-        scan_desc = heap_beginscan(graph_edge_label, snapshot, 0, NULL);
-        /* get the tupdesc - we don't need to release this one */
-        tupdesc = RelationGetDescr(graph_edge_label);
-        /* bail if the number of columns differs */
-        if (tupdesc->natts != 4)
-            ereport(ERROR,
-                    (errcode(ERRCODE_UNDEFINED_TABLE),
-                     errmsg("Invalid number of attributes for %s.%s",
-                     vlegctx->graph_name, edge_label_name)));
-        /* get all tuples in table and insert them into graph hashtables */
-        while((tuple = heap_getnext(scan_desc, ForwardScanDirection)) != NULL)
-        {
-            graphid edge_id;
-            graphid edge_vertex_start_id;
-            graphid edge_vertex_end_id;
-            Datum edge_properties;
-            bool inserted = false;
-
-            /* something is wrong if this isn't true */
-            Assert(HeapTupleIsValid(tuple));
-            /* get the edge id */
-            edge_id = DatumGetInt64(column_get_datum(tupdesc, tuple, 0, "id",
-                                                     GRAPHIDOID, true));
-            /* get the edge start_id (start vertex id) */
-            edge_vertex_start_id = DatumGetInt64(column_get_datum(tupdesc,
-                                                                  tuple, 1,
-                                                                  "start_id",
-                                                                  GRAPHIDOID,
-                                                                  true));
-            /* get the edge end_id (end vertex id)*/
-            edge_vertex_end_id = DatumGetInt64(column_get_datum(tupdesc, tuple,
-                                                                2, "end_id",
-                                                                GRAPHIDOID,
-                                                                true));
-            /* get the edge properties datum */
-            edge_properties = column_get_datum(tupdesc, tuple, 3, "properties",
-                                               AGTYPEOID, true);
-
-            /* insert edge into edge hashtable */
-            inserted = insert_edge(vlegctx, edge_id, edge_properties,
-                                   edge_vertex_start_id, edge_vertex_end_id,
-                                   edge_label_table_oid);
-            /* this insert must not fail */
-            if (!inserted)
-            {
-                 elog(ERROR, "insert_edge: failed to insert");
-            }
-
-            /* insert the edge into this vertex's edge list */
-            inserted = insert_vertex_edge(vlegctx, edge_vertex_start_id,
-                                          edge_id);
-            /* this insert must not fail */
-            if (!inserted)
-            {
-                 elog(ERROR, "insert_vertex_edge: failed to insert");
-            }
-
-            /*
-             * Insert the edge into this vertex's edge list. UNLESS this is a
-             * self loop (start == end  vertex) because that would be adding it
-             * twice.
-             */
-            if (edge_vertex_start_id != edge_vertex_end_id)
-            {
-                inserted = insert_vertex_edge(vlegctx, edge_vertex_end_id,
-                                              edge_id);
-                /* this insert much not fail */
-                if (!inserted)
-                {
-                     elog(ERROR, "insert_vertex_edge: failed to insert");
-                }
-            }
-        }
-
-        /* end the scan and close the relation */
-        heap_endscan(scan_desc);
-        heap_close(graph_edge_label, ShareLock);
-    }
-}
-
-/*
- * Helper function to freeze the VLE hashtables from additional inserts. This
- * may, or may not, be useful. Currently, these hashtables are only seen by the
- * creating process and only for reading.
- */
-static void freeze_VLE_global_hashtables(VLE_global_context *vlegctx)
-{
-    hash_freeze(vlegctx->vertex_hashtable);
-    hash_freeze(vlegctx->edge_hashtable);
-}
-
-/*
- * Helper function to free the entire specified context. After running this
- * you should not use the pointer in vlegctx.
- */
-static void free_specific_global_context(VLE_global_context *vlegctx)
-{
-    GraphIdNode *curr_vertex = NULL;
-
-    /* don't do anything if NULL */
-    if (vlegctx == NULL)
-    {
-        return;
-    }
-
-    /* free the graph name */
-    pfree(vlegctx->graph_name);
-
-    /* free the vertex edge lists, starting with the head */
-    curr_vertex = vlegctx->vertices->head;
-    while (curr_vertex != NULL)
-    {
-        GraphIdNode *next_vertex = NULL;
-        vertex_entry *value = NULL;
-        bool found = false;
-        graphid vertex_id;
-
-        /* get the next vertex in the list, if any */
-        next_vertex = curr_vertex->next;
-
-        /* get the current vertex id */
-        vertex_id = curr_vertex->id;
-
-        /* retrieve the vertex entry */
-        value = (vertex_entry *)hash_search(vlegctx->vertex_hashtable,
-                                            (void *)&vertex_id, HASH_FIND,
-                                            &found);
-        /* this is bad if it isn't found */
-        Assert(found);
-
-        /* free the edge list associated with this vertex */
-        free_ListGraphId(value->edges);
-
-        /* move to the next vertex */
-        curr_vertex = next_vertex;
-    }
-
-    /* free the vertices list */
-    free_ListGraphId(vlegctx->vertices);
-
-    /* free the hashtables */
-    hash_destroy(vlegctx->vertex_hashtable);
-    hash_destroy(vlegctx->edge_hashtable);
-
-    /* free the context */
-    pfree(vlegctx);
-}
-
-/*
- * Helper function to manage the VLE global contexts. It will create the context
- * for the graph specified, provided it isn't already built and valid. During
- * processing it will free (delete) all invalid contexts. It returns the global
- * context for the specified graph.
- */
-static VLE_global_context *manage_VLE_global_contexts(char *graph_name,
-                                                      Oid graph_oid)
-{
-    VLE_global_context *new_vlegctx = NULL;
-    VLE_global_context *curr_vlegctx = NULL;
-    VLE_global_context *prev_vlegctx = NULL;
-    MemoryContext oldctx = NULL;
-
-    /* we need a higher context, or one that isn't destroyed by SRF exit */
-    oldctx = MemoryContextSwitchTo(TopMemoryContext);
-
-    /*
-     * We need to see if any global contexts already exist and if any do for
-     * this particular graph. There are 5 possibilities -
-     *
-     *     1) There are no global contexts.
-     *     2) One does exist for this graph but, is invalid.
-     *     3) One does exist for this graph and is valid.
-     *     4) One or more other contexts do exist and all are valid.
-     *     5) One or more other contexts do exist but, one or more are invalid.
-     */
-
-    /* free the invalidated global contexts first */
-    prev_vlegctx = NULL;
-    curr_vlegctx = global_vle_contexts;
-    while (curr_vlegctx != NULL)
-    {
-        VLE_global_context *next_vlegctx = curr_vlegctx->next;
-
-        /* if the transaction ids have changed, we have an invalid graph */
-        if (curr_vlegctx->xmin != GetActiveSnapshot()->xmin ||
-            curr_vlegctx->xmax != GetActiveSnapshot()->xmax)
-        {
-            /*
-             * If prev_vlegctx is NULL then we are freeing the top of the
-             * contexts. So, we need to point the global variable to the
-             * new (next) top context, if there is one.
-             */
-            if (prev_vlegctx == NULL)
-            {
-                global_vle_contexts = next_vlegctx;
-            }
-            else
-            {
-                prev_vlegctx->next = curr_vlegctx->next;
-            }
-
-            /* free the current graph context */
-            free_specific_global_context(curr_vlegctx);
-        }
-        else
-        {
-            prev_vlegctx = curr_vlegctx;
-        }
-
-        /* advance to the next context */
-        curr_vlegctx = next_vlegctx;
-    }
-
-    /* find our graph's context. if it exists, we are done */
-    curr_vlegctx = global_vle_contexts;
-    while (curr_vlegctx != NULL)
-    {
-        if (curr_vlegctx->graph_oid == graph_oid)
-        {
-            /* switch our context back */
-            MemoryContextSwitchTo(oldctx);
-            /* we are done */
-            return curr_vlegctx;
-        }
-        curr_vlegctx = curr_vlegctx->next;
-    }
-
-    /* otherwise, we need to create one and possibly attach it */
-    new_vlegctx = palloc0(sizeof(VLE_global_context));
-
-    if (global_vle_contexts != NULL)
-    {
-        new_vlegctx->next = global_vle_contexts;
-    }
-    else
-    {
-        new_vlegctx->next = NULL;
-    }
-
-    /* set the global context variable */
-    global_vle_contexts = new_vlegctx;
-
-    /* set the graph name and oid */
-    new_vlegctx->graph_name = pstrdup(graph_name);
-    new_vlegctx->graph_oid = graph_oid;
-
-    /* set the transaction ids */
-    new_vlegctx->xmin = GetActiveSnapshot()->xmin;
-    new_vlegctx->xmax = GetActiveSnapshot()->xmax;
-
-    /* initialize our vertices list */
-    new_vlegctx->vertices = NULL;
-
-    /* build the hashtables for this graph */
-    create_VLE_global_hashtables(new_vlegctx);
-    load_VLE_global_hashtables(new_vlegctx);
-    freeze_VLE_global_hashtables(new_vlegctx);
-
-    /* switch back to the previous memory context */
-    MemoryContextSwitchTo(oldctx);
-
-    return new_vlegctx;
-}
-
 /* helper function to check if our start and end vertices exist */
 static bool do_vsid_and_veid_exist(VLE_local_context *vlelctx)
 {
@@ -1220,18 +465,18 @@ static bool do_vsid_and_veid_exist(VLE_local_context *vlelctx)
     if (vlelctx->path_function == VLE_FUNCTION_PATHS_FROM ||
         vlelctx->path_function == VLE_FUNCTION_PATHS_ALL)
     {
-        return (get_vertex_entry(vlelctx, vlelctx->vsid) != NULL);
+        return (get_vertex_entry(vlelctx->ggctx, vlelctx->vsid) != NULL);
     }
 
     /* if we are only using the ending vertex */
     if (vlelctx->path_function == VLE_FUNCTION_PATHS_TO)
     {
-        return (get_vertex_entry(vlelctx, vlelctx->veid) != NULL);
+        return (get_vertex_entry(vlelctx->ggctx, vlelctx->veid) != NULL);
     }
 
     /* if we are using both start and end */
-    return ((get_vertex_entry(vlelctx, vlelctx->vsid) != NULL) &&
-            (get_vertex_entry(vlelctx, vlelctx->veid) != NULL));
+    return ((get_vertex_entry(vlelctx->ggctx, vlelctx->vsid) != NULL) &&
+            (get_vertex_entry(vlelctx->ggctx, vlelctx->veid) != NULL));
 }
 
 /* load the initial edges into the dfs_edge_stack */
@@ -1252,11 +497,11 @@ static void load_initial_dfs_stacks(VLE_local_context *vlelctx)
 
 /*
  * Helper function to build the local VLE context. This is also the point
- * where, if necessary, the global contexts are created and freed.
+ * where, if necessary, the global GRAPH contexts are created and freed.
  */
 static VLE_local_context *build_local_vle_context(FunctionCallInfo fcinfo)
 {
-    VLE_global_context *vlegctx = NULL;
+    GRAPH_global_context *ggctx = NULL;
     VLE_local_context *vlelctx = NULL;
     agtype_value *agtv_temp = NULL;
     char *graph_name = NULL;
@@ -1271,10 +516,10 @@ static VLE_local_context *build_local_vle_context(FunctionCallInfo fcinfo)
     graph_oid = get_graph_oid(graph_name);
 
     /*
-     * Create or retrieve the VLE global context for this graph. This function
+     * Create or retrieve the GRAPH global context for this graph. This function
      * will also purge off invalidated contexts.
     */
-    vlegctx = manage_VLE_global_contexts(graph_name, graph_oid);
+    ggctx = manage_GRAPH_global_contexts(graph_name, graph_oid);
 
     /* allocate and initialize local VLE context */
     vlelctx = palloc0(sizeof(VLE_local_context));
@@ -1283,18 +528,14 @@ static VLE_local_context *build_local_vle_context(FunctionCallInfo fcinfo)
     vlelctx->graph_name = graph_name;
     vlelctx->graph_oid = graph_oid;
 
-    /* set the global context referenced by this local context */
-    vlelctx->vlegctx = vlegctx;
-
-    /* set the hashtables used by this context */
-    vlelctx->vertex_hashtable = vlegctx->vertex_hashtable;
-    vlelctx->edge_hashtable = vlegctx->edge_hashtable;
+    /* set the global context referenced by this local VLE context */
+    vlelctx->ggctx = ggctx;
 
     /* initialize the path function */
     vlelctx->path_function = VLE_FUNCTION_PATHS_BETWEEN;
 
     /* initialize the next vertex, in this case the first */
-    vlelctx->next_vertex = vlegctx->vertices->head;
+    vlelctx->next_vertex = peek_stack_head(get_graph_vertices(ggctx));
 
     /* if there isn't one, the graph is empty */
     if (vlelctx->next_vertex == NULL)
@@ -1313,9 +554,9 @@ static VLE_local_context *build_local_vle_context(FunctionCallInfo fcinfo)
         vlelctx->path_function = VLE_FUNCTION_PATHS_TO;
 
         /* get the start vertex */
-        vlelctx->vsid = vlelctx->next_vertex->id;
+        vlelctx->vsid = get_graphid(vlelctx->next_vertex);
         /* increment to the next vertex */
-        vlelctx->next_vertex = vlelctx->next_vertex->next;
+        vlelctx->next_vertex = next_GraphIdNode(vlelctx->next_vertex);
     }
     else
     {
@@ -1422,9 +663,9 @@ static VLE_local_context *build_local_vle_context(FunctionCallInfo fcinfo)
     create_VLE_local_state_hashtable(vlelctx);
 
     /* initialize the dfs stacks */
-    vlelctx->dfs_vertex_stack = new_stack();
-    vlelctx->dfs_edge_stack = new_stack();
-    vlelctx->dfs_path_stack = new_stack();
+    vlelctx->dfs_vertex_stack = new_graphid_stack();
+    vlelctx->dfs_edge_stack = new_graphid_stack();
+    vlelctx->dfs_path_stack = new_graphid_stack();
 
     /* load in the starting edge(s) */
     load_initial_dfs_stacks(vlelctx);
@@ -1459,122 +700,6 @@ static edge_state_entry *get_edge_state(VLE_local_context *vlelctx,
 }
 
 /*
- * Helper function to retrieve a vertex_entry from the graph's vertex hash
- * table. If there isn't one, it returns a NULL. The latter is necessary for
- * checking if the vsid and veid entries exist.
- */
-static vertex_entry *get_vertex_entry(VLE_local_context *vlelctx,
-                                      graphid vertex_id)
-{
-    vertex_entry *ve = NULL;
-    bool found = false;
-
-    /* retrieve the current vertex entry */
-    ve = (vertex_entry *)hash_search(vlelctx->vertex_hashtable,
-                                     (void *)&vertex_id, HASH_FIND, &found);
-    return ve;
-}
-
-/* helper function to retrieve an edge_entry from the graph's edge hash table */
-static edge_entry *get_edge_entry(VLE_local_context *vlelctx, graphid edge_id)
-{
-    edge_entry *ee = NULL;
-    bool found = false;
-
-    /* retrieve the current edge entry */
-    ee = (edge_entry *)hash_search(vlelctx->edge_hashtable, (void *)&edge_id,
-                                   HASH_FIND, &found);
-    /* it should be found, otherwise we have problems */
-    Assert(found);
-
-    return ee;
-}
-
-/* helper function to create a new, empty, stack */
-static ListGraphId *new_stack(void)
-{
-    ListGraphId *stack = NULL;
-
-    /* allocate the container for the stack */
-    stack = palloc0(sizeof(ListGraphId));
-
-    /* set it to its initial values */
-    stack->head = NULL;
-    stack->tail = NULL;
-    stack->size = 0;
-
-    /* return the new stack */
-    return stack;
-}
-
-/* helper function to free a stack's contents but, not the container */
-static void free_stack(ListGraphId *stack)
-{
-    Assert(stack != NULL);
-
-    /* while there are entries */
-    while (stack->head != NULL)
-    {
-        /* get the next element in the stack */
-        GraphIdNode *next = stack->head->next;
-
-        /* free the head element */
-        pfree(stack->head);
-        /* move the head to the next */
-        stack->head = next;
-    }
-
-    /* reset the tail and size */
-    stack->tail = NULL;
-    stack->size = 0;
-}
-
-/*
- * Helper function for a generic push id (int64) to a stack. If the stack is
- * NULL, it will error out.
- */
-static void push_stack(ListGraphId *stack, graphid id)
-{
-    GraphIdNode *new_node = NULL;
-
-    Assert(stack != NULL);
-
-    /* create the new element */
-    new_node = palloc0(sizeof(GraphIdNode));
-    new_node->id = id;
-
-    /* insert (push) the new element on the top */
-    new_node->next = stack->head;
-    stack->head = new_node;
-    stack->size++;
-}
-
-/*
- * Helper function for a generic pop id (int64) from a stack. If the stack is
- * empty, it will error out. You should verify that the stack isn't empty prior
- * to calling.
- */
-static graphid pop_stack(ListGraphId *stack)
-{
-    GraphIdNode *node = NULL;
-    graphid id;
-
-    Assert(stack != NULL);
-    Assert(stack->size != 0);
-
-    /* remove the element from the top of the stack */
-    node = stack->head;
-    id = node->id;
-    stack->head = stack->head->next;
-    stack->size--;
-    /* free the element */
-    pfree(node);
-
-    /* return the id */
-    return id;
-}
-
-/*
  * Helper function to get the id of the next vertex to move to. This is to
  * simplify finding the next vertex due to the VLE edge's direction.
  */
@@ -1586,11 +711,11 @@ static graphid get_next_vertex(VLE_local_context *vlelctx, edge_entry *ee)
     switch (vlelctx->edge_direction)
     {
         case CYPHER_REL_DIR_RIGHT:
-            terminal_vertex_id = ee->end_vertex_id;
+            terminal_vertex_id = get_edge_entry_end_vertex_id(ee);
             break;
 
         case CYPHER_REL_DIR_LEFT:
-            terminal_vertex_id = ee->start_vertex_id;
+            terminal_vertex_id = get_edge_entry_start_vertex_id(ee);
             break;
 
         case CYPHER_REL_DIR_NONE:
@@ -1604,15 +729,15 @@ static graphid get_next_vertex(VLE_local_context *vlelctx, edge_entry *ee)
              * as un-directional, where we go to next depends on where we came
              * from. This is because we can go against an edge.
              */
-            parent_vertex_id = PEEK_STACK(vertex_stack);
+            parent_vertex_id = PEEK_GRAPHID_STACK(vertex_stack);
             /* find the terminal vertex */
-            if (ee->start_vertex_id == parent_vertex_id)
+            if (get_edge_entry_start_vertex_id(ee) == parent_vertex_id)
             {
-                terminal_vertex_id = ee->end_vertex_id;
+                terminal_vertex_id = get_edge_entry_end_vertex_id(ee);
             }
-            else if (ee->end_vertex_id == parent_vertex_id)
+            else if (get_edge_entry_end_vertex_id(ee) == parent_vertex_id)
             {
-                terminal_vertex_id = ee->start_vertex_id;
+                terminal_vertex_id = get_edge_entry_start_vertex_id(ee);
             }
             else
             {
@@ -1657,7 +782,7 @@ static bool dfs_find_a_path_between(VLE_local_context *vlelctx)
     end_vertex_id = vlelctx->veid;
 
     /* while we have edges to process */
-    while (!(IS_STACK_EMPTY(edge_stack)))
+    while (!(IS_GRAPHID_STACK_EMPTY(edge_stack)))
     {
         graphid edge_id;
         graphid next_vertex_id;
@@ -1666,7 +791,7 @@ static bool dfs_find_a_path_between(VLE_local_context *vlelctx)
         bool found = false;
 
         /* get an edge, but leave it on the stack for now */
-        edge_id = PEEK_STACK(edge_stack);
+        edge_id = PEEK_GRAPHID_STACK(edge_stack);
         /* get the edge's state */
         ese = get_edge_state(vlelctx, edge_id);
         /*
@@ -1682,18 +807,18 @@ static bool dfs_find_a_path_between(VLE_local_context *vlelctx)
             graphid path_edge_id;
 
             /* get the edge id on the top of the path stack (last edge) */
-            path_edge_id = PEEK_STACK(path_stack);
+            path_edge_id = PEEK_GRAPHID_STACK(path_stack);
             /*
              * If the ids are the same, we're backing up. So, remove it from the
              * path stack and reset used_in_path.
              */
             if (edge_id == path_edge_id)
             {
-                pop_stack(path_stack);
+                pop_graphid_stack(path_stack);
                 ese->used_in_path = false;
             }
             /* now remove it from the edge stack */
-            pop_stack(edge_stack);
+            pop_graphid_stack(edge_stack);
             /*
              * Remove its source vertex, if we are looking at edges as
              * un-directional. We only maintain the vertex stack when the
@@ -1702,7 +827,7 @@ static bool dfs_find_a_path_between(VLE_local_context *vlelctx)
              */
             if (vlelctx->edge_direction == CYPHER_REL_DIR_NONE)
             {
-                pop_stack(vertex_stack);
+                pop_graphid_stack(vertex_stack);
             }
             /* move to the next edge */
             continue;
@@ -1713,10 +838,10 @@ static bool dfs_find_a_path_between(VLE_local_context *vlelctx)
          * the edge stack as it is already there.
          */
         ese->used_in_path = true;
-        push_stack(path_stack, edge_id);
+        push_graphid_stack(path_stack, edge_id);
 
         /* now get the edge entry so we can get the next vertex to move to */
-        ee = get_edge_entry(vlelctx, edge_id);
+        ee = get_edge_entry(vlelctx->ggctx, edge_id);
         next_vertex_id = get_next_vertex(vlelctx, ee);
 
         /*
@@ -1724,8 +849,9 @@ static bool dfs_find_a_path_between(VLE_local_context *vlelctx)
          * within the bounds specified?
          */
         if (next_vertex_id == end_vertex_id &&
-            path_stack->size >= vlelctx->lidx &&
-            (vlelctx->uidx_infinite || path_stack->size <= vlelctx->uidx))
+            get_stack_size(path_stack) >= vlelctx->lidx &&
+            (vlelctx->uidx_infinite ||
+             get_stack_size(path_stack) <= vlelctx->uidx))
         {
             /* we found one */
             found = true;
@@ -1737,14 +863,14 @@ static bool dfs_find_a_path_between(VLE_local_context *vlelctx)
          */
         if (next_vertex_id == end_vertex_id &&
             !vlelctx->uidx_infinite &&
-            path_stack->size > vlelctx->uidx)
+            get_stack_size(path_stack) > vlelctx->uidx)
         {
             continue;
         }
 
         /* add in the edges for the next vertex if we won't exceed the bounds */
         if (vlelctx->uidx_infinite ||
-            path_stack->size < vlelctx->uidx)
+            get_stack_size(path_stack) < vlelctx->uidx)
         {
             add_valid_vertex_edges(vlelctx, next_vertex_id);
         }
@@ -1784,7 +910,7 @@ static bool dfs_find_a_path_from(VLE_local_context *vlelctx)
     path_stack = vlelctx->dfs_path_stack;
 
     /* while we have edges to process */
-    while (!(IS_STACK_EMPTY(edge_stack)))
+    while (!(IS_GRAPHID_STACK_EMPTY(edge_stack)))
     {
         graphid edge_id;
         graphid next_vertex_id;
@@ -1793,7 +919,7 @@ static bool dfs_find_a_path_from(VLE_local_context *vlelctx)
         bool found = false;
 
         /* get an edge, but leave it on the stack for now */
-        edge_id = PEEK_STACK(edge_stack);
+        edge_id = PEEK_GRAPHID_STACK(edge_stack);
         /* get the edge's state */
         ese = get_edge_state(vlelctx, edge_id);
         /*
@@ -1809,18 +935,18 @@ static bool dfs_find_a_path_from(VLE_local_context *vlelctx)
             graphid path_edge_id;
 
             /* get the edge id on the top of the path stack (last edge) */
-            path_edge_id = PEEK_STACK(path_stack);
+            path_edge_id = PEEK_GRAPHID_STACK(path_stack);
             /*
              * If the ids are the same, we're backing up. So, remove it from the
              * path stack and reset used_in_path.
              */
             if (edge_id == path_edge_id)
             {
-                pop_stack(path_stack);
+                pop_graphid_stack(path_stack);
                 ese->used_in_path = false;
             }
             /* now remove it from the edge stack */
-            pop_stack(edge_stack);
+            pop_graphid_stack(edge_stack);
             /*
              * Remove its source vertex, if we are looking at edges as
              * un-directional. We only maintain the vertex stack when the
@@ -1829,7 +955,7 @@ static bool dfs_find_a_path_from(VLE_local_context *vlelctx)
              */
             if (vlelctx->edge_direction == CYPHER_REL_DIR_NONE)
             {
-                pop_stack(vertex_stack);
+                pop_graphid_stack(vertex_stack);
             }
             /* move to the next edge */
             continue;
@@ -1840,18 +966,19 @@ static bool dfs_find_a_path_from(VLE_local_context *vlelctx)
          * the edge stack as it is already there.
          */
         ese->used_in_path = true;
-        push_stack(path_stack, edge_id);
+        push_graphid_stack(path_stack, edge_id);
 
         /* now get the edge entry so we can get the next vertex to move to */
-        ee = get_edge_entry(vlelctx, edge_id);
+        ee = get_edge_entry(vlelctx->ggctx, edge_id);
         next_vertex_id = get_next_vertex(vlelctx, ee);
 
         /*
          * Is this a path that meets our requirements? Is its length within the
          * bounds specified?
          */
-        if (path_stack->size >= vlelctx->lidx &&
-            (vlelctx->uidx_infinite || path_stack->size <= vlelctx->uidx))
+        if (get_stack_size(path_stack) >= vlelctx->lidx &&
+            (vlelctx->uidx_infinite ||
+             get_stack_size(path_stack) <= vlelctx->uidx))
         {
             /* we found one */
             found = true;
@@ -1859,7 +986,7 @@ static bool dfs_find_a_path_from(VLE_local_context *vlelctx)
 
         /* add in the edges for the next vertex if we won't exceed the bounds */
         if (vlelctx->uidx_infinite ||
-            path_stack->size < vlelctx->uidx)
+            get_stack_size(path_stack) < vlelctx->uidx)
         {
             add_valid_vertex_edges(vlelctx, next_vertex_id);
         }
@@ -1884,17 +1011,17 @@ static bool is_edge_in_path(VLE_local_context *vlelctx, graphid edge_id)
     GraphIdNode *edge = NULL;
 
     /* start at the top of the stack */
-    edge = vlelctx->dfs_path_stack->head;
+    edge = peek_stack_head(vlelctx->dfs_path_stack);
 
     /* go through the path stack, return true if we find the edge */
     while (edge != NULL)
     {
-        if (edge->id == edge_id)
+        if (get_graphid(edge) == edge_id)
         {
             return true;
         }
         /* get the next stack element */
-        edge = edge->next;
+        edge = next_GraphIdNode(edge);
     }
     /* we didn't find it if we get here */
     return false;
@@ -1921,16 +1048,16 @@ static void add_valid_vertex_edges(VLE_local_context *vlelctx,
     GraphIdNode *edge = NULL;
 
     /* get the vertex entry */
-    ve = get_vertex_entry(vlelctx, vertex_id);
+    ve = get_vertex_entry(vlelctx->ggctx, vertex_id);
     /* there better be a valid vertex */
     Assert(ve != NULL);
     /* point to stacks */
     vertex_stack = vlelctx->dfs_vertex_stack;
     edge_stack = vlelctx->dfs_edge_stack;
     /* get a pointer to the first edge */
-    if (ve->edges != NULL)
+    if (get_vertex_entry_edges(ve) != NULL)
     {
-        edge = ve->edges->head;
+        edge = peek_stack_head(get_vertex_entry_edges(ve));
     }
     else
     {
@@ -1944,29 +1071,29 @@ static void add_valid_vertex_edges(VLE_local_context *vlelctx,
         graphid edge_id;
 
         /* get the edge_id */
-        edge_id = edge->id;
+        edge_id = get_graphid(edge);
 
         /*
          * This is a fast existence check, relative to the hash search, for when
          * the path stack is small.
          */
-        if (vlelctx->dfs_path_stack->size < 10 &&
+        if (get_stack_size(vlelctx->dfs_path_stack) < 10 &&
             is_edge_in_path(vlelctx, edge_id))
         {
-            edge = edge->next;
+            edge = next_GraphIdNode(edge);
             continue;
         }
 
         /* get the edge entry */
-        ee = get_edge_entry(vlelctx, edge_id);
+        ee = get_edge_entry(vlelctx->ggctx, edge_id);
         /* it better exist */
         Assert(ee != NULL);
 
         /* is the edge going in the correct direction */
         if ((vlelctx->edge_direction == CYPHER_REL_DIR_NONE) ||
-            (vertex_id == ee->start_vertex_id &&
+            (vertex_id == get_edge_entry_start_vertex_id(ee) &&
              vlelctx->edge_direction == CYPHER_REL_DIR_RIGHT) ||
-            (vertex_id == ee->end_vertex_id &&
+            (vertex_id == get_edge_entry_end_vertex_id(ee) &&
              vlelctx->edge_direction == CYPHER_REL_DIR_LEFT))
         {
             /* get its state */
@@ -2001,13 +1128,14 @@ static void add_valid_vertex_edges(VLE_local_context *vlelctx,
                      */
                     if (vlelctx->edge_direction == CYPHER_REL_DIR_NONE)
                     {
-                        push_stack(vertex_stack, ve->vertex_id);
+                        push_graphid_stack(vertex_stack,
+                                           get_vertex_entry_id(ve));
                     }
-                    push_stack(edge_stack, edge_id);
+                    push_graphid_stack(edge_stack, edge_id);
                 }
             }
         }
-        edge = edge->next;
+        edge = next_GraphIdNode(edge);
     }
 }
 
@@ -2091,7 +1219,7 @@ static VLE_path_container *build_VLE_path_container(VLE_local_context *vlelctx)
     }
 
     /* allocate the graphid array */
-    ssize = stack->size;
+    ssize = get_stack_size(stack);
 
     /*
      * Create the container. Note that the path size will always be 2 times the
@@ -2110,7 +1238,7 @@ static VLE_path_container *build_VLE_path_container(VLE_local_context *vlelctx)
     graphid_array[0] = vid;
 
     /* get the head of the stack */
-    edge = stack->head;
+    edge = peek_stack_head(stack);
 
     /*
      * We need to fill in the array from the back to the front. This is due
@@ -2126,8 +1254,8 @@ static VLE_path_container *build_VLE_path_container(VLE_local_context *vlelctx)
         Assert(index > 0);
 
         /* store and set to the next edge */
-        graphid_array[index] = edge->id;
-        edge = edge->next;
+        graphid_array[index] = get_graphid(edge);
+        edge = next_GraphIdNode(edge);
 
         /* we need to skip over the interior vertices */
         index -= 2;
@@ -2138,9 +1266,10 @@ static VLE_path_container *build_VLE_path_container(VLE_local_context *vlelctx)
     {
         edge_entry *ee = NULL;
 
-        ee = get_edge_entry(vlelctx, graphid_array[index]);
-        vid = (vid == ee->start_vertex_id) ? ee->end_vertex_id :
-                                             ee->start_vertex_id;
+        ee = get_edge_entry(vlelctx->ggctx, graphid_array[index]);
+        vid = (vid == get_edge_entry_start_vertex_id(ee)) ?
+                   get_edge_entry_end_vertex_id(ee) :
+                   get_edge_entry_start_vertex_id(ee);
         graphid_array[index+1] = vid;
     }
 
@@ -2157,7 +1286,7 @@ static VLE_path_container *build_VLE_zero_container(VLE_local_context *vlelctx)
     graphid vid = 0;
 
     /* we should have an empty stack */
-    Assert(stack->size == 0);
+    Assert(get_stack_size(stack) == 0);
 
     /*
      * Create the container. Note that the path size will always be 1 as this is
@@ -2179,33 +1308,6 @@ static VLE_path_container *build_VLE_zero_container(VLE_local_context *vlelctx)
 }
 
 /*
- * Helper function to find the VLE_global_context used by the specified
- * graph_oid. If not found, it returns NULL.
- */
-static VLE_global_context *find_VLE_global_context(Oid graph_oid)
-{
-    VLE_global_context *vlegctx = NULL;
-
-    /* get the root */
-    vlegctx = global_vle_contexts;
-
-    while(vlegctx != NULL)
-    {
-        /* if we found it return it */
-        if (vlegctx->graph_oid == graph_oid)
-        {
-            return vlegctx;
-        }
-
-        /* advance to the next context */
-        vlegctx = vlegctx->next;
-    }
-
-    /* we did not find it so return NULL */
-    return NULL;
-}
-
-/*
  * Helper function to build an AGTV_ARRAY of edges from an array of graphids.
  *
  * Note: You should free the array when done. Although, it should be freed
@@ -2213,8 +1315,7 @@ static VLE_global_context *find_VLE_global_context(Oid graph_oid)
  */
 static agtype_value *build_edge_list(VLE_path_container *vpc)
 {
-    VLE_global_context *vlegctx = NULL;
-    VLE_local_context vlelctx;
+    GRAPH_global_context *ggctx = NULL;
     agtype_in_state edges_result;
     Oid graph_oid = InvalidOid;
     graphid *graphid_array = NULL;
@@ -2224,15 +1325,10 @@ static agtype_value *build_edge_list(VLE_path_container *vpc)
     /* get the graph_oid */
     graph_oid = vpc->graph_oid;
 
-    /* get the global context for this graph */
-    vlegctx = find_VLE_global_context(graph_oid);
+    /* get the GRAPH global context for this graph */
+    ggctx = find_GRAPH_global_context(graph_oid);
     /* verify we got a global context */
-    Assert(vlegctx != NULL);
-
-    /* build a temporary local context for the hash searches */
-    MemSet(&vlelctx, 0, sizeof(VLE_local_context));
-    vlelctx.vertex_hashtable = vlegctx->vertex_hashtable;
-    vlelctx.edge_hashtable = vlegctx->edge_hashtable;
+    Assert(ggctx != NULL);
 
     /* get the graphid_array and size */
     graphid_array = GET_GRAPHID_ARRAY_FROM_CONTAINER(vpc);
@@ -2250,14 +1346,14 @@ static agtype_value *build_edge_list(VLE_path_container *vpc)
         agtype_value *agtv_edge = NULL;
 
         /* get the edge entry from the hashtable */
-        ee = get_edge_entry(&vlelctx, graphid_array[index]);
+        ee = get_edge_entry(ggctx, graphid_array[index]);
         /* get the label name from the oid */
-        label_name = get_rel_name(ee->edge_label_table_oid);
+        label_name = get_rel_name(get_edge_entry_label_table_oid(ee));
         /* reconstruct the edge */
-        agtv_edge = agtype_value_build_edge(ee->edge_id, label_name,
-                                            ee->end_vertex_id,
-                                            ee->start_vertex_id,
-                                            ee->edge_properties);
+        agtv_edge = agtype_value_build_edge(get_edge_entry_id(ee), label_name,
+                                            get_edge_entry_end_vertex_id(ee),
+                                            get_edge_entry_start_vertex_id(ee),
+                                            get_edge_entry_properties(ee));
         /* push the edge*/
         edges_result.res = push_agtype_value(&edges_result.parse_state,
                                              WAGT_ELEM, agtv_edge);
@@ -2283,8 +1379,7 @@ static agtype_value *build_edge_list(VLE_path_container *vpc)
  */
 static agtype_value *build_path(VLE_path_container *vpc)
 {
-    VLE_global_context *vlegctx = NULL;
-    VLE_local_context vlelctx;
+    GRAPH_global_context *ggctx = NULL;
     agtype_in_state path_result;
     Oid graph_oid = InvalidOid;
     graphid *graphid_array = NULL;
@@ -2294,15 +1389,10 @@ static agtype_value *build_path(VLE_path_container *vpc)
     /* get the graph_oid */
     graph_oid = vpc->graph_oid;
 
-    /* get the global context for this graph */
-    vlegctx = find_VLE_global_context(graph_oid);
+    /* get the GRAPH global context for this graph */
+    ggctx = find_GRAPH_global_context(graph_oid);
     /* verify we got a global context */
-    Assert(vlegctx != NULL);
-
-    /* build a temporary local context for the hash searches */
-    MemSet(&vlelctx, 0, sizeof(VLE_local_context));
-    vlelctx.vertex_hashtable = vlegctx->vertex_hashtable;
-    vlelctx.edge_hashtable = vlegctx->edge_hashtable;
+    Assert(ggctx != NULL);
 
     /* get the graphid_array and size */
     graphid_array = GET_GRAPHID_ARRAY_FROM_CONTAINER(vpc);
@@ -2322,12 +1412,13 @@ static agtype_value *build_path(VLE_path_container *vpc)
         agtype_value *agtv_edge = NULL;
 
         /* get the vertex entry from the hashtable */
-        ve = get_vertex_entry(&vlelctx, graphid_array[index]);
+        ve = get_vertex_entry(ggctx, graphid_array[index]);
         /* get the label name from the oid */
-        label_name = get_rel_name(ve->vertex_label_table_oid);
+        label_name = get_rel_name(get_vertex_entry_label_table_oid(ve));
         /* reconstruct the vertex */
-        agtv_vertex = agtype_value_build_vertex(ve->vertex_id, label_name,
-                                                ve->vertex_properties);
+        agtv_vertex = agtype_value_build_vertex(get_vertex_entry_id(ve),
+                                                label_name,
+                                                get_vertex_entry_properties(ve));
         /* push the vertex */
         path_result.res = push_agtype_value(&path_result.parse_state, WAGT_ELEM,
                                             agtv_vertex);
@@ -2342,14 +1433,14 @@ static agtype_value *build_path(VLE_path_container *vpc)
         }
 
         /* get the edge entry from the hashtable */
-        ee = get_edge_entry(&vlelctx, graphid_array[index+1]);
+        ee = get_edge_entry(ggctx, graphid_array[index+1]);
         /* get the label name from the oid */
-        label_name = get_rel_name(ee->edge_label_table_oid);
+        label_name = get_rel_name(get_edge_entry_label_table_oid(ee));
         /* reconstruct the edge */
-        agtv_edge = agtype_value_build_edge(ee->edge_id, label_name,
-                                            ee->end_vertex_id,
-                                            ee->start_vertex_id,
-                                            ee->edge_properties);
+        agtv_edge = agtype_value_build_edge(get_edge_entry_id(ee), label_name,
+                                            get_edge_entry_end_vertex_id(ee),
+                                            get_edge_entry_start_vertex_id(ee),
+                                            get_edge_entry_properties(ee));
         /* push the edge*/
         path_result.res = push_agtype_value(&path_result.parse_state, WAGT_ELEM,
                                             agtv_edge);
@@ -2500,10 +1591,10 @@ Datum age_vle(PG_FUNCTION_ARGS)
                  (vlelctx->path_function == VLE_FUNCTION_PATHS_TO))
         {
             /* get the next start vertex id */
-            vlelctx->vsid = vlelctx->next_vertex->id;
+            vlelctx->vsid = get_graphid(vlelctx->next_vertex);
 
             /* increment to the next vertex */
-            vlelctx->next_vertex = vlelctx->next_vertex->next;
+            vlelctx->next_vertex = next_GraphIdNode(vlelctx->next_vertex);
 
             /* load in the starting edge(s) */
             load_initial_dfs_stacks(vlelctx);
@@ -3095,9 +2186,9 @@ Datum _ag_enforce_edge_uniqueness(PG_FUNCTION_ARGS)
     exists_ctl.entrysize = sizeof(int64);
     exists_ctl.hash = tag_hash;
 
-    /* create hash table */
-    exists_hash = hash_create("edges", 1000, &exists_ctl,
-                              HASH_ELEM | HASH_FUNCTION);
+    /* create exists_hash table */
+    exists_hash = hash_create(EXISTS_HTAB_NAME, EXISTS_HTAB_NAME_INITIAL_SIZE,
+                              &exists_ctl, HASH_ELEM | HASH_FUNCTION);
 
     /* insert arguments into hash table */
     for (i = 0; i < nargs; i++)
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index e90c908..43d24a9 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -52,9 +52,9 @@
 #include "utils/snapmgr.h"
 #include "utils/typcache.h"
 
+#include "utils/age_vle.h"
 #include "utils/agtype.h"
 #include "utils/agtype_parser.h"
-#include "utils/agtype_vle.h"
 #include "utils/ag_float8_supp.h"
 #include "catalog/ag_graph.h"
 #include "catalog/ag_label.h"
@@ -9208,4 +9208,4 @@ Datum age_unnest(PG_FUNCTION_ARGS)
     rsi->setDesc = ret_tdesc;
 
     PG_RETURN_NULL();
-}
\ No newline at end of file
+}
diff --git a/src/include/utils/age_global_graph.h b/src/include/utils/age_global_graph.h
new file mode 100644
index 0000000..891b0eb
--- /dev/null
+++ b/src/include/utils/age_global_graph.h
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef AG_AGE_GLOBAL_GRAPH_H
+#define AG_AGE_GLOBAL_GRAPH_H
+
+#include "utils/graphid.h"
+#include "utils/age_graphid_ds.h"
+
+/*
+ * We declare the graph nodes and edges here, and in this way, so that it may be
+ * used elsewhere. However, we keep the contents private by defining it in
+ * age_global_graph.c
+ */
+
+/* vertex entry for the vertex_hastable */
+typedef struct vertex_entry vertex_entry;
+
+/* edge entry for the edge_hashtable */
+typedef struct edge_entry edge_entry;
+
+typedef struct GRAPH_global_context GRAPH_global_context;
+
+/* GRAPH global context functions */
+GRAPH_global_context *manage_GRAPH_global_contexts(char *graph_name,
+                                                   Oid graph_oid);
+GRAPH_global_context *find_GRAPH_global_context(Oid graph_oid);
+/* GRAPH retrieval functions */
+inline ListGraphId *get_graph_vertices(GRAPH_global_context *ggctx);
+vertex_entry *get_vertex_entry(GRAPH_global_context *ggctx,
+                               graphid vertex_id);
+edge_entry *get_edge_entry(GRAPH_global_context *ggctx, graphid edge_id);
+/* vertex entry accessor functions*/
+inline graphid get_vertex_entry_id(vertex_entry *ve);
+inline ListGraphId *get_vertex_entry_edges(vertex_entry *ve);
+inline Oid get_vertex_entry_label_table_oid(vertex_entry *ve);
+inline Datum get_vertex_entry_properties(vertex_entry *ve);
+/* edge entry accessor functions */
+inline graphid get_edge_entry_id(edge_entry *ee);
+inline Oid get_edge_entry_label_table_oid(edge_entry *ee);
+inline Datum get_edge_entry_properties(edge_entry *ee);
+inline graphid get_edge_entry_start_vertex_id(edge_entry *ee);
+inline graphid get_edge_entry_end_vertex_id(edge_entry *ee);
+#endif
diff --git a/src/include/utils/age_graphid_ds.h b/src/include/utils/age_graphid_ds.h
new file mode 100644
index 0000000..52f12d7
--- /dev/null
+++ b/src/include/utils/age_graphid_ds.h
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef AG_AGE_GRAPHID_DS_H
+#define AG_AGE_GRAPHID_DS_H
+
+#define IS_GRAPHID_STACK_EMPTY(stack) \
+            get_stack_size(stack) == 0
+#define PEEK_GRAPHID_STACK(stack) \
+            (graphid) get_graphid(peek_stack_head(stack))
+
+/*
+ * We declare the GRAPHID data structures here, and in this way, so that they
+ * may be used elsewhere. However, we keep the contents private by defining them
+ * in age_graphid_ds.c
+ */
+
+/* declare the GraphIdNode */
+typedef struct GraphIdNode GraphIdNode;
+
+/* declare the ListGraphId container */
+typedef struct ListGraphId ListGraphId;
+
+/* GraphIdNode access functions */
+inline GraphIdNode *next_GraphIdNode(GraphIdNode *node);
+inline graphid get_graphid(GraphIdNode *node);
+
+/* graphid stack functions */
+/* create a new ListGraphId stack */
+ListGraphId *new_graphid_stack(void);
+/* free a ListGraphId stack */
+void free_graphid_stack(ListGraphId *stack);
+/* push a graphid onto a ListGraphId stack */
+void push_graphid_stack(ListGraphId *stack, graphid id);
+/* pop (remove) a GraphIdNode from the top of the stack */
+graphid pop_graphid_stack(ListGraphId *stack);
+/* peek (doesn't remove) at the head entry of a ListGraphId stack */
+inline GraphIdNode *peek_stack_head(ListGraphId *stack);
+/* peek (doesn't remove) at the tail entry of a ListGraphId stack */
+inline GraphIdNode *peek_stack_tail(ListGraphId *stack);
+/* return the size of a ListGraphId stack */
+inline int64 get_stack_size(ListGraphId *stack);
+
+/* graphid list functions */
+/*
+ * Helper function to add a graphid to the end of a ListGraphId container.
+ * If the container is NULL, it creates the container with the entry.
+ */
+ListGraphId *append_graphid(ListGraphId *container, graphid id);
+/* free a ListGraphId container */
+void free_ListGraphId(ListGraphId *container);
+
+#endif
diff --git a/src/include/utils/agtype_vle.h b/src/include/utils/age_vle.h
similarity index 96%
rename from src/include/utils/agtype_vle.h
rename to src/include/utils/age_vle.h
index 93c57b2..27106d2 100644
--- a/src/include/utils/agtype_vle.h
+++ b/src/include/utils/age_vle.h
@@ -20,7 +20,8 @@
 #ifndef AG_AGTYPE_VLE_H
 #define AG_AGTYPE_VLE_H
 
-#include "postgres.h"
+#include "utils/agtype.h"
+#include "utils/age_global_graph.h"
 
 /*
  * We declare the VLE_path_container here, and in this way, so that it may be