diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index 7222665..2931329 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-REINDEX { INDEX | TABLE | DATABASE | SYSTEM } <replaceable class="PARAMETER">name</replaceable> [ FORCE ]
+REINDEX { INDEX | TABLE | DATABASE | SYSTEM } <replaceable class="PARAMETER">name</replaceable> [ FORCE ] [ CONCURRENTLY ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -68,9 +68,10 @@ REINDEX { INDEX | TABLE | DATABASE | SYSTEM } <replaceable class="PARAMETER">nam
       An index build with the <literal>CONCURRENTLY</> option failed, leaving
       an <quote>invalid</> index. Such indexes are useless but it can be
       convenient to use <command>REINDEX</> to rebuild them. Note that
-      <command>REINDEX</> will not perform a concurrent build. To build the
-      index without interfering with production you should drop the index and
-      reissue the <command>CREATE INDEX CONCURRENTLY</> command.
+      <command>REINDEX</> will not perform a concurrent build if <literal>
+      CONCURRENTLY</> is not specified. To build the index without interfering
+      with production you should drop the index and reissue the <command>CREATE
+      INDEX CONCURRENTLY</> or <command>REINDEX CONCURRENTLY</> command.
      </para>
     </listitem>
 
@@ -139,6 +140,21 @@ REINDEX { INDEX | TABLE | DATABASE | SYSTEM } <replaceable class="PARAMETER">nam
    </varlistentry>
 
    <varlistentry>
+    <term><literal>CONCURRENTLY</literal></term>
+    <listitem>
+     <para>
+      When this option is used, <productname>PostgreSQL</> will rebuild the
+      index without taking any locks that prevent concurrent inserts,
+      updates, or deletes on the table; whereas a standard reindex build
+      locks out writes (but not reads) on the table until it's done.
+      There are several caveats to be aware of when using this option
+      &mdash; see <xref linkend="SQL-REINDEX-CONCURRENTLY"
+      endterm="SQL-REINDEX-CONCURRENTLY-title">.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>FORCE</literal></term>
     <listitem>
      <para>
@@ -231,6 +247,93 @@ REINDEX { INDEX | TABLE | DATABASE | SYSTEM } <replaceable class="PARAMETER">nam
    to be reindexed by separate commands.  This is still possible, but
    redundant.
   </para>
+
+
+  <refsect2 id="SQL-REINDEX-CONCURRENTLY">
+   <title id="SQL-REINDEX-CONCURRENTLY-title">Rebuilding Indexes Concurrently</title>
+
+   <indexterm zone="SQL-REINDEX-CONCURRENTLY">
+   <primary>index</primary>
+   <secondary>rebuilding concurrently</secondary>
+   </indexterm>
+
+   <para>
+    Rebuilding an index can interfere with regular operation of a database.
+    Normally <productname>PostgreSQL</> locks the table whose index is rebuilt
+    against writes and performs the entire index build with a single scan of the
+    table. Other transactions can still read the table, but if they try to
+    insert, update, or delete rows in the table they will block until the
+    index rebuild is finished. This could have a severe effect if the system is
+    a live production database.  Very large tables can take many hours to be
+    indexed, and even for smaller tables, an index rebuild can lock out writers
+    for periods that are unacceptably long for a production system.
+   </para>
+
+   <para>
+    <productname>PostgreSQL</> supports rebuilding indexes without locking
+    out writes.  This method is invoked by specifying the
+    <literal>CONCURRENTLY</> option of <command>REINDEX</>.
+    When this option is used, <productname>PostgreSQL</> must perform two
+    scans of the table for each index that needs to be rebuild and in
+    addition it must wait for all existing transactions that could potentially
+    use the index to terminate. This method requires more total work than a
+    standard index rebuild and takes significantly longer to complete as it
+    needs to wait for unfinished transactiions that might modify the index.
+    However, since it allows normal operations to continue while the index
+    is rebuilt, this method is useful for rebuilding indexes in a production
+    environment.  Of course, the extra CPU, memory and I/O load imposed by
+    the index rebuild might slow other operations.
+   </para>
+
+   <para>
+    In a concurrent index build, a new index that will replace the one to
+    be rebuild is actually entered into the system catalogs in one transaction,
+    then two table scans occur in two more transactions and to make the new
+    index valid from the other backends.  Once this is performed, the old
+    and fresh indexes are swapped in, and the old index is marked as invalid
+    in a third transaction. Finally two additional transactions are used to mark
+    the old index as not ready and then drop it.
+   </para>
+
+   <para>
+    If a problem arises while rebuilding the indexes, such as a
+    uniqueness violation in a unique index, the <command>REINDEX</>
+    command will fail but leave behind an <quote>invalid</> new index on top
+    of the existing one. This index will be ignored for querying purposes
+    because it might be incomplete; however it will still consume update
+    overhead. The <application>psql</> <command>\d</> command will report
+    such an index as <literal>INVALID</>:
+
+<programlisting>
+postgres=# \d tab
+       Table "public.tab"
+ Column |  Type   | Modifiers
+--------+---------+-----------
+ col    | integer |
+Indexes:
+    "idx" btree (col)
+    "idx_cct" btree (col) INVALID
+</programlisting>
+
+    The recommended recovery method in such cases is to drop the concurrent
+    index and try again to perform <command>REINDEX CONCURRENTLY</> once again.
+    The concurrent index created during the processing has a name finishing by
+    the suffix cct.
+   </para>
+
+   <para>
+    Regular index builds permit other regular index builds on the
+    same table to occur in parallel, but only one concurrent index build
+    can occur on a table at a time.  In both cases, no other types of schema
+    modification on the table are allowed meanwhile.  Another difference
+    is that a regular <command>REINDEX TABLE</> or <command>REINDEX INDEX</>
+    command can be performed within a transaction block, but
+    <command>REINDEX CONCURRENTLY</> cannot. <command>REINDEX DATABASE</> is
+    by default not allowed to run inside a transaction block, so in this case
+    <command>CONCURRENTLY</> is not supported.
+   </para>
+
+  </refsect2>
  </refsect1>
 
  <refsect1>
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 464950b..ca41255 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1076,6 +1076,267 @@ index_create(Relation heapRelation,
 	return indexRelationId;
 }
 
+
+/*
+ * index_concurrent_create
+ *
+ * Create an index based on the given one that will be used for concurrent
+ * operations. The index is inserted into catalogs and needs to be built later
+ * on. This is called during concurrent index processing. The heap relation
+ * on which is based the index needs to be closed by the caller.
+ */
+Oid
+index_concurrent_create(Relation heapRelation, Oid indOid, char *concurrentName)
+{
+	Relation	indexRelation;
+	IndexInfo  *indexInfo;
+	Oid			concurrentOid = InvalidOid;
+	List	   *columnNames = NIL;
+	int			i;
+	HeapTuple	indexTuple;
+	Datum       indclassDatum, indoptionDatum;
+	oidvector  *indclass;
+	int2vector *indcoloptions;
+	bool		isnull;
+
+	indexRelation = index_open(indOid, RowExclusiveLock);
+
+	/* Concurrent index uses the same index information as former index */
+	indexInfo = BuildIndexInfo(indexRelation);
+
+	/* Build the list of column names, necessary for index_create */
+	for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+	{
+		AttrNumber	attnum = indexInfo->ii_KeyAttrNumbers[i];
+		Form_pg_attribute attform = heapRelation->rd_att->attrs[attnum - 1];;
+
+		/* Pick up column name from the relation */
+		columnNames = lappend(columnNames, pstrdup(NameStr(attform->attname)));
+	}
+
+	/* Get the array of class and column options IDs from index info */
+	indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indOid));
+    if (!HeapTupleIsValid(indexTuple))
+        elog(ERROR, "cache lookup failed for index %u", indOid);
+	indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
+                                    Anum_pg_index_indclass, &isnull);
+    Assert(!isnull);
+    indclass = (oidvector *) DatumGetPointer(indclassDatum);
+
+	indoptionDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
+									 Anum_pg_index_indoption, &isnull);
+    Assert(!isnull);
+	indcoloptions = (int2vector *) DatumGetPointer(indoptionDatum);
+
+	/* Now create the concurrent index */
+	concurrentOid = index_create(heapRelation,
+								 (const char*)concurrentName,
+								 InvalidOid,
+								 InvalidOid,
+								 indexInfo,
+								 columnNames,
+								 indexRelation->rd_rel->relam,
+								 indexRelation->rd_rel->reltablespace,
+								 indexRelation->rd_indcollation,
+								 indclass->values,
+								 indcoloptions->values,
+								 (Datum) indexRelation->rd_options, // This needs to be checked
+								 indexRelation->rd_index->indisprimary,
+								 false,	/* is constraint? */
+								 false,	/* is deferrable? */
+								 false,	/* is initially deferred? */
+								 false,	/* allow table to be a system catalog? */
+								 true,	/* skip build? */
+								 true); /* concurrent? */
+
+	/* Close the relations used and clean up */
+	index_close(indexRelation, RowExclusiveLock);
+	ReleaseSysCache(indexTuple);
+
+	return concurrentOid;
+}
+
+
+/*
+ * index_concurrent_build
+ *
+ * Build index for a concurrent operation. Low-level locks are taken when this
+ * operation is performed.
+ */
+void
+index_concurrent_build(Oid heapOid,
+					   Oid indexOid,
+					   bool isprimary)
+{
+	Relation	rel,
+				indexRelation;
+	IndexInfo  *indexInfo;
+
+    /* Open and lock the parent heap relation */
+    rel = heap_open(heapOid, ShareUpdateExclusiveLock);
+
+    /* And the target index relation */
+    indexRelation = index_open(indexOid, RowExclusiveLock);
+
+    /* We have to re-build the IndexInfo struct, since it was lost in commit */
+    indexInfo = BuildIndexInfo(indexRelation);
+    Assert(!indexInfo->ii_ReadyForInserts);
+    indexInfo->ii_Concurrent = true;
+    indexInfo->ii_BrokenHotChain = false;
+
+    /* Now build the index */
+    index_build(rel, indexRelation, indexInfo, isprimary, false);
+
+    /* Close both the relations, but keep the locks */
+    heap_close(rel, NoLock);
+    index_close(indexRelation, NoLock);
+}
+
+
+/*
+ * index_concurrent_mark
+ *
+ * Update the pg_index row to mark the index with a new status. All the
+ * operations that can be performed on the index marking are listed in
+ * IndexMarkOperation.
+ * When a marking modification is done, the caller needs to commit current
+ * transaction as any new transactions that open the table might perform
+ * read or write operations on the table related.
+ * - INDEX_MARK_READY, index is marked as ready for inserts. When marked as
+ *	 ready, the index needs to be invalid.
+ * - INDEX_MARK_NOT_READY, index is marked as not ready for inserts. When
+ *   marked as not ready, the index needs to be already invalid.
+ * - INDEX_MARK_VALID, index is marked as valid for selects. When marked as
+ *	 valid, the index needs to be ready.
+ * - INDEX_MARK_NOT_VALID, index is marked as not valid for selects, When
+ *   marked as not valid, the index needs to be ready.
+ */
+void
+index_concurrent_mark(Oid indOid, IndexMarkOperation operation)
+{
+	Relation		pg_index;
+	HeapTuple		indexTuple;
+	Form_pg_index	indexForm;
+
+	pg_index = heap_open(IndexRelationId, RowExclusiveLock);
+
+	indexTuple = SearchSysCacheCopy1(INDEXRELID,
+									 ObjectIdGetDatum(indOid));
+	if (!HeapTupleIsValid(indexTuple))
+		elog(ERROR, "cache lookup failed for index %u", indOid);
+	indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
+
+	switch(operation)
+	{
+		case INDEX_MARK_READY:
+			Assert(!indexForm->indisready);
+			Assert(!indexForm->indisvalid);
+			indexForm->indisready = true;
+			break;
+
+		case INDEX_MARK_NOT_READY:
+			Assert(indexForm->indisready);
+			Assert(!indexForm->indisvalid);
+			indexForm->indisready = false;
+			break;
+
+		case INDEX_MARK_VALID:
+			Assert(indexForm->indisready);
+			Assert(!indexForm->indisvalid);
+			indexForm->indisvalid = true;
+			break;
+
+		case INDEX_MARK_NOT_VALID:
+			Assert(indexForm->indisready);
+			Assert(indexForm->indisvalid);
+			indexForm->indisvalid = false;
+			break;
+
+		default:
+			/* Do nothing */
+			break;
+	}
+
+	simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
+	CatalogUpdateIndexes(pg_index, indexTuple);
+
+	heap_close(pg_index, RowExclusiveLock);
+}
+
+
+/*
+ * index_concurrent_swap
+ *
+ * Replace old index by old index in a concurrent context. For the time being
+ * what is done here is switching the relation names of the indexes. If extra
+ * operations are necessary during a concurrent swap, processing should be
+ * added here.
+ */
+void
+index_concurrent_swap(Oid newIndexOid, Oid oldIndexOid)
+{
+	char	nameNew[NAMEDATALEN],
+			nameOld[NAMEDATALEN],
+			nameTemp[NAMEDATALEN];
+
+	/* The new index is going to use the name of the old index */
+	snprintf(nameNew, NAMEDATALEN, "%s", get_rel_name(newIndexOid));
+	snprintf(nameOld, NAMEDATALEN, "%s", get_rel_name(oldIndexOid));
+
+	/* Change the name of old index to something temporary */
+	snprintf(nameTemp, NAMEDATALEN, "cct_%d", oldIndexOid);
+	RenameRelationInternal(oldIndexOid, nameTemp);
+
+	/* Make the catalog update visible */
+	CommandCounterIncrement();
+
+	/* Change the name of the new index with the old one */
+	RenameRelationInternal(newIndexOid, nameOld);
+
+	/* Make the catalog update visible */
+	CommandCounterIncrement();
+
+	/* Finally change the name of old index with name of the new one */
+	RenameRelationInternal(oldIndexOid, nameNew);
+
+	/* Make the catalog update visible */
+	CommandCounterIncrement();
+}
+
+
+/*
+ * index_concurrent_drop
+ *
+ * Drop a list of indexes in a concurrent process. Deletion has to be done
+ * through performDeletion or dependencies of the index are not dropped.
+ */
+void
+index_concurrent_drop(List *indexIds)
+{
+	ListCell		   *lc;
+	ObjectAddresses	   *objects = new_object_addresses();
+
+	Assert(indexIds != NIL);
+
+	/* Scan the list of indexes and build object list */
+	foreach(lc, indexIds)
+	{
+		Oid				indexOid = lfirst_oid(lc);
+		ObjectAddress	object;
+
+		object.classId = RelationRelationId;
+		object.objectId = indexOid;
+		object.objectSubId = 0;
+
+		/* Add object to list */
+		add_exact_object_address(&object, objects);
+	}
+
+	/* Perform deletion */
+	performMultipleDeletions(objects, DROP_CASCADE, 0);
+}
+
+
 /*
  * index_constraint_create
  *
@@ -2939,6 +3200,8 @@ reindex_index(Oid indexId, bool skip_constraint_checks)
 	/*
 	 * Open and lock the parent heap relation.	ShareLock is sufficient since
 	 * we only need to be sure no schema or data changes are going on.
+	 * In the case of concurrent operation, a lower-level lock is taken to
+	 * allow INSERT/UPDATE/DELETE operations.
 	 */
 	heapId = IndexGetRelation(indexId, false);
 	heapRelation = heap_open(heapId, ShareLock);
@@ -2946,6 +3209,8 @@ reindex_index(Oid indexId, bool skip_constraint_checks)
 	/*
 	 * Open the target index relation and get an exclusive lock on it, to
 	 * ensure that no one else is touching this particular index.
+	 * For concurrent operation, a lower lock is taken to allow INSERT, UPDATE
+	 * and DELETE operations.
 	 */
 	iRel = index_open(indexId, AccessExclusiveLock);
 
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index a58101e..d9fc8e4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -68,12 +68,15 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo,
 static Oid GetIndexOpClass(List *opclass, Oid attrType,
 				char *accessMethodName, Oid accessMethodId);
 static char *ChooseIndexName(const char *tabname, Oid namespaceId,
-				List *colnames, List *exclusionOpNames,
-				bool primary, bool isconstraint);
+							 List *colnames, List *exclusionOpNames,
+							 bool primary, bool isconstraint,
+							 bool concurrent);
 static char *ChooseIndexNameAddition(List *colnames);
 static List *ChooseIndexColumnNames(List *indexElems);
 static void RangeVarCallbackForReindexIndex(const RangeVar *relation,
 								Oid relId, Oid oldRelId, void *arg);
+static void WaitForVirtualLocks(LOCKTAG heaplocktag);
+static void WaitForOldSnapshots(Snapshot snapshot);
 
 /*
  * CheckIndexCompatible
@@ -305,7 +308,6 @@ DefineIndex(IndexStmt *stmt,
 	Oid			tablespaceId;
 	List	   *indexColNames;
 	Relation	rel;
-	Relation	indexRelation;
 	HeapTuple	tuple;
 	Form_pg_am	accessMethodForm;
 	bool		amcanorder;
@@ -314,16 +316,9 @@ DefineIndex(IndexStmt *stmt,
 	int16	   *coloptions;
 	IndexInfo  *indexInfo;
 	int			numberOfAttributes;
-	VirtualTransactionId *old_lockholders;
-	VirtualTransactionId *old_snapshots;
-	int			n_old_snapshots;
 	LockRelId	heaprelid;
 	LOCKTAG		heaplocktag;
 	Snapshot	snapshot;
-	Relation	pg_index;
-	HeapTuple	indexTuple;
-	Form_pg_index indexForm;
-	int			i;
 
 	/*
 	 * count attributes in index
@@ -449,7 +444,8 @@ DefineIndex(IndexStmt *stmt,
 											indexColNames,
 											stmt->excludeOpNames,
 											stmt->primary,
-											stmt->isconstraint);
+											stmt->isconstraint,
+											false);
 
 	/*
 	 * look up the access method, verify it can handle the requested features
@@ -659,18 +655,8 @@ DefineIndex(IndexStmt *stmt,
 	 * one of the transactions in question is blocked trying to acquire an
 	 * exclusive lock on our table.  The lock code will detect deadlock and
 	 * error out properly.
-	 *
-	 * Note: GetLockConflicts() never reports our own xid, hence we need not
-	 * check for that.	Also, prepared xacts are not reported, which is fine
-	 * since they certainly aren't going to do anything more.
 	 */
-	old_lockholders = GetLockConflicts(&heaplocktag, ShareLock);
-
-	while (VirtualTransactionIdIsValid(*old_lockholders))
-	{
-		VirtualXactLock(*old_lockholders, true);
-		old_lockholders++;
-	}
+	WaitForVirtualLocks(heaplocktag);
 
 	/*
 	 * At this moment we are sure that there are no transactions with the
@@ -690,50 +676,20 @@ DefineIndex(IndexStmt *stmt,
 	 * HOT-chain or the extension of the chain is HOT-safe for this index.
 	 */
 
-	/* Open and lock the parent heap relation */
-	rel = heap_openrv(stmt->relation, ShareUpdateExclusiveLock);
-
-	/* And the target index relation */
-	indexRelation = index_open(indexRelationId, RowExclusiveLock);
-
 	/* Set ActiveSnapshot since functions in the indexes may need it */
-	PushActiveSnapshot(GetTransactionSnapshot());
-
-	/* We have to re-build the IndexInfo struct, since it was lost in commit */
-	indexInfo = BuildIndexInfo(indexRelation);
-	Assert(!indexInfo->ii_ReadyForInserts);
-	indexInfo->ii_Concurrent = true;
-	indexInfo->ii_BrokenHotChain = false;
-
-	/* Now build the index */
-	index_build(rel, indexRelation, indexInfo, stmt->primary, false);
+    PushActiveSnapshot(GetTransactionSnapshot());
 
-	/* Close both the relations, but keep the locks */
-	heap_close(rel, NoLock);
-	index_close(indexRelation, NoLock);
+	/* Perform concurrent build of index */
+	index_concurrent_build(RangeVarGetRelid(stmt->relation, NoLock, false),
+						   indexRelationId,
+						   stmt->primary);
 
 	/*
 	 * Update the pg_index row to mark the index as ready for inserts. Once we
 	 * commit this transaction, any new transactions that open the table must
 	 * insert new entries into the index for insertions and non-HOT updates.
 	 */
-	pg_index = heap_open(IndexRelationId, RowExclusiveLock);
-
-	indexTuple = SearchSysCacheCopy1(INDEXRELID,
-									 ObjectIdGetDatum(indexRelationId));
-	if (!HeapTupleIsValid(indexTuple))
-		elog(ERROR, "cache lookup failed for index %u", indexRelationId);
-	indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
-
-	Assert(!indexForm->indisready);
-	Assert(!indexForm->indisvalid);
-
-	indexForm->indisready = true;
-
-	simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
-	CatalogUpdateIndexes(pg_index, indexTuple);
-
-	heap_close(pg_index, RowExclusiveLock);
+	index_concurrent_mark(indexRelationId, INDEX_MARK_READY);
 
 	/* we can do away with our snapshot */
 	PopActiveSnapshot();
@@ -750,13 +706,7 @@ DefineIndex(IndexStmt *stmt,
 	 * We once again wait until no transaction can have the table open with
 	 * the index marked as read-only for updates.
 	 */
-	old_lockholders = GetLockConflicts(&heaplocktag, ShareLock);
-
-	while (VirtualTransactionIdIsValid(*old_lockholders))
-	{
-		VirtualXactLock(*old_lockholders, true);
-		old_lockholders++;
-	}
+	WaitForVirtualLocks(heaplocktag);
 
 	/*
 	 * Now take the "reference snapshot" that will be used by validate_index()
@@ -785,105 +735,277 @@ DefineIndex(IndexStmt *stmt,
 	 * The index is now valid in the sense that it contains all currently
 	 * interesting tuples.	But since it might not contain tuples deleted just
 	 * before the reference snap was taken, we have to wait out any
-	 * transactions that might have older snapshots.  Obtain a list of VXIDs
-	 * of such transactions, and wait for them individually.
-	 *
-	 * We can exclude any running transactions that have xmin > the xmin of
-	 * our reference snapshot; their oldest snapshot must be newer than ours.
-	 * We can also exclude any transactions that have xmin = zero, since they
-	 * evidently have no live snapshot at all (and any one they might be in
-	 * process of taking is certainly newer than ours).  Transactions in other
-	 * DBs can be ignored too, since they'll never even be able to see this
-	 * index.
+	 * transactions that might have older snapshots.
+	 */
+	WaitForOldSnapshots(snapshot);
+
+	/*
+	 * Index can now be marked valid -- update its pg_index entry
+	 */
+	index_concurrent_mark(indexRelationId, INDEX_MARK_VALID);
+
+	/*
+	 * The pg_index update will cause backends (including this one) to update
+	 * relcache entries for the index itself, but we should also send a
+	 * relcache inval on the parent table to force replanning of cached plans.
+	 * Otherwise existing sessions might fail to use the new index where it
+	 * would be useful.  (Note that our earlier commits did not create reasons
+	 * to replan; relcache flush on the index itself was sufficient.)
+	 */
+	CacheInvalidateRelcacheByRelid(heaprelid.relId);
+
+	/* we can now do away with our active snapshot */
+	PopActiveSnapshot();
+
+	/* And we can remove the validating snapshot too */
+	UnregisterSnapshot(snapshot);
+
+	/*
+	 * Last thing to do is release the session-level lock on the parent table.
+	 */
+	UnlockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
+
+	return indexRelationId;
+}
+
+
+/*
+ * ReindexConcurrent
+ *
+ * Process REINDEX CONCURRENTLY for given list of indexes.
+ * Each reindexing step is done simultaneously for all the given
+ * indexes. If no list of indexes is given by the caller, all the
+ * indexes included in the relation will be reindexed.
+ */
+bool
+ReindexConcurrentIndexes(Oid heapOid, List *indexIds)
+{
+	Relation	heapRelation;
+	List	   *concurrentIndexIds = NIL,
+			   *indexLocks = NIL,
+			   *realIndexIds = indexIds;
+	ListCell   *lc, *lc2;
+	LockRelId	heapLockId;
+	LOCKTAG		heapLocktag;
+	Snapshot	snapshot;
+
+	/*
+	 * Phase 1 of REINDEX CONCURRENTLY
 	 *
-	 * We can also exclude autovacuum processes and processes running manual
-	 * lazy VACUUMs, because they won't be fazed by missing index entries
-	 * either.	(Manual ANALYZEs, however, can't be excluded because they
-	 * might be within transactions that are going to do arbitrary operations
-	 * later.)
+	 * Here begins the process for rebuilding concurrently the index.
+	 * We need first to create an index which is based on the same data
+	 * as the former index except that it will be only registered in catalogs
+	 * and will be built after.
+	 */
+	/* lock level used here should match index lock index_concurrent_create() */
+	heapRelation = heap_open(heapOid, ShareUpdateExclusiveLock);
+
+	/*
+	 * If relation has a toast relation, it needs to be reindexed too,
+	 * but this cannot be done concurrently.
+	 */
+	if (OidIsValid(heapRelation->rd_rel->reltoastrelid))
+		reindex_relation(heapRelation->rd_rel->reltoastrelid,
+						 REINDEX_REL_PROCESS_TOAST);
+
+	/* Get the list of indexes from relation if caller has not given anything */
+	if (realIndexIds == NIL)
+		realIndexIds = RelationGetIndexList(heapRelation);
+
+	/* Definetely no indexes, so leave */
+	if (realIndexIds == NIL)
+	{
+		heap_close(heapRelation, NoLock);
+		return false;
+	}
+
+	/* Relation on which is based index cannot be shared */
+	if (heapRelation->rd_rel->relisshared)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("concurrent reindex is not supported for shared relations")));
+
+	/* Do the concurrent index creation for each index */
+	foreach(lc, realIndexIds)
+	{
+		char	   *concurrentName;
+		Oid			indOid = lfirst_oid(lc);
+		Oid			concurrentOid = InvalidOid;
+		Relation	indexRel,
+					indexConcurrentRel;
+		LockRelId	lockrelid;
+
+		indexRel = index_open(indOid, ShareUpdateExclusiveLock);
+
+		/* Concurrent reindex of index for exclusion constraint is not supported. */
+		if (indexRel->rd_index->indisexclusion)
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("concurrent reindex is not supported for exclusion constraints")));
+
+		/* Choose a relation name for concurrent index */
+		concurrentName = ChooseIndexName(get_rel_name(indOid),
+										 get_rel_namespace(heapOid),
+										 NULL,
+										 false,
+										 false,
+										 false,
+										 true);
+
+		/* Create concurrent index based on given index */
+		concurrentOid = index_concurrent_create(heapRelation, indOid, concurrentName);
+
+		/* Now open the relation of concurrent index, a lock is also needed on it */
+		indexConcurrentRel = index_open(concurrentOid, ShareUpdateExclusiveLock);
+
+		/* Save the concurrent index Oid */
+		concurrentIndexIds = lappend_oid(concurrentIndexIds, concurrentOid);
+
+		/*
+		 * Save lockrelid to protect each concurrent relation from drop
+		 * then close relations.
+		 */
+		lockrelid = indexRel->rd_lockInfo.lockRelId;
+		indexLocks = lappend(indexLocks, &lockrelid);
+		lockrelid = indexConcurrentRel->rd_lockInfo.lockRelId;
+		indexLocks = lappend(indexLocks, &lockrelid);
+
+		index_close(indexRel, NoLock);
+		index_close(indexConcurrentRel, NoLock);
+	}
+
+	/*
+	 * Save the heap lock for following visibility checks with other backends
+	 * might conflict with this session.
+	 */
+	heapLockId = heapRelation->rd_lockInfo.lockRelId;
+	SET_LOCKTAG_RELATION(heapLocktag, heapLockId.dbId, heapLockId.relId);
+
+	/* Close heap relation */
+	heap_close(heapRelation, NoLock);
+
+	/*
+	 * For a concurrent build, it is necessary to make the catalog entries
+	 * visible to the other transactions before actually building the index.
+	 * This will prevent them from making incompatible HOT updates. The index
+	 * is marked as not ready and invalid so as no other transactions will try
+	 * to use it for INSERT or SELECT.
 	 *
-	 * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not
-	 * check for that.
+	 * Before committing, get a session level lock on the relation, the
+	 * concurrent index and its copy to insure that none of them are dropped
+	 * until the operation is done.
+	 */
+	LockRelationIdForSession(&heapLockId, ShareUpdateExclusiveLock);
+
+	/* Lock each index and each concurrent index accordingly */
+	foreach(lc, indexLocks)
+	{
+		LockRelId lockRel = * (LockRelId *) lfirst(lc);
+		LockRelationIdForSession(&lockRel, ShareUpdateExclusiveLock);
+	}
+
+	PopActiveSnapshot();
+	CommitTransactionCommand();
+	StartTransactionCommand();
+
+	/*
+	 * Phase 2 of REINDEX CONCURRENTLY
 	 *
-	 * If a process goes idle-in-transaction with xmin zero, we do not need to
-	 * wait for it anymore, per the above argument.  We do not have the
-	 * infrastructure right now to stop waiting if that happens, but we can at
-	 * least avoid the folly of waiting when it is idle at the time we would
-	 * begin to wait.  We do this by repeatedly rechecking the output of
-	 * GetCurrentVirtualXIDs.  If, during any iteration, a particular vxid
-	 * doesn't show up in the output, we know we can forget about it.
+	 * We need to wait until no running transactions could have the table open with
+	 * the old list of indexes. A concurrent build is done for each concurrent
+	 * index that will replace the old indexes. All those indexes share the same
+	 * snapshot and they are built in the same transaction.
 	 */
-	old_snapshots = GetCurrentVirtualXIDs(snapshot->xmin, true, false,
-										  PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
-										  &n_old_snapshots);
+	WaitForVirtualLocks(heapLocktag);
 
-	for (i = 0; i < n_old_snapshots; i++)
+	/* Set ActiveSnapshot since functions in the indexes may need it */
+    PushActiveSnapshot(GetTransactionSnapshot());
+
+	/* Get the first element of concurrent index list */
+	lc2 = list_head(concurrentIndexIds);
+
+	foreach(lc, realIndexIds)
 	{
-		if (!VirtualTransactionIdIsValid(old_snapshots[i]))
-			continue;			/* found uninteresting in previous cycle */
+		Relation	indexRel;
+		Oid			indOid = lfirst_oid(lc);
+		Oid			concurrentOid = lfirst_oid(lc2);
+		bool		primary;
 
-		if (i > 0)
-		{
-			/* see if anything's changed ... */
-			VirtualTransactionId *newer_snapshots;
-			int			n_newer_snapshots;
-			int			j;
-			int			k;
+		/* Move to next concurrent item */
+		lc2 = lnext(lc2);
 
-			newer_snapshots = GetCurrentVirtualXIDs(snapshot->xmin,
-													true, false,
-										 PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
-													&n_newer_snapshots);
-			for (j = i; j < n_old_snapshots; j++)
-			{
-				if (!VirtualTransactionIdIsValid(old_snapshots[j]))
-					continue;	/* found uninteresting in previous cycle */
-				for (k = 0; k < n_newer_snapshots; k++)
-				{
-					if (VirtualTransactionIdEquals(old_snapshots[j],
-												   newer_snapshots[k]))
-						break;
-				}
-				if (k >= n_newer_snapshots)		/* not there anymore */
-					SetInvalidVirtualTransactionId(old_snapshots[j]);
-			}
-			pfree(newer_snapshots);
-		}
+		/* Index relation has been closed by previous commit, so reopen it */
+		indexRel = index_open(indOid, ShareUpdateExclusiveLock);
+		primary = indexRel->rd_index->indisprimary;
+		index_close(indexRel, ShareUpdateExclusiveLock);
 
-		if (VirtualTransactionIdIsValid(old_snapshots[i]))
-			VirtualXactLock(old_snapshots[i], true);
+		/* Perform concurrent build of new index */
+		index_concurrent_build(heapOid,
+							   concurrentOid,
+							   primary);
+
+		/*
+		 * Update the pg_index row of the concurrent index as ready for inserts.
+		 * Once we commit this transaction, any new transactions that open the table
+		 * must insert new entries into the index for insertions and non-HOT updates.
+		 */
+		index_concurrent_mark(concurrentOid, INDEX_MARK_READY);
 	}
 
+	/* we can do away with our snapshot */
+	PopActiveSnapshot();
+
 	/*
-	 * Index can now be marked valid -- update its pg_index entry
+	 * Commit this transaction to make the indisready update visible for
+	 * concurrent index.
 	 */
-	pg_index = heap_open(IndexRelationId, RowExclusiveLock);
+	CommitTransactionCommand();
+	StartTransactionCommand();
 
-	indexTuple = SearchSysCacheCopy1(INDEXRELID,
-									 ObjectIdGetDatum(indexRelationId));
-	if (!HeapTupleIsValid(indexTuple))
-		elog(ERROR, "cache lookup failed for index %u", indexRelationId);
-	indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
+	/*
+	 * Phase 3 of REINDEX CONCURRENTLY
+	 *
+	 * During this phase the concurrent indexes catch up with the INSERT that
+	 * might have occurred in the parent table and are marked as valid once done.
+	 *
+	 * We once again wait until no transaction can have the table open with
+	 * the index marked as read-only for updates.
+	 */
+	WaitForVirtualLocks(heapLocktag);
 
-	Assert(indexForm->indisready);
-	Assert(!indexForm->indisvalid);
+	/*
+	 * Take the reference snapshot that will be used for the concurrent indexes
+	 * validation.
+	 */
+	snapshot = RegisterSnapshot(GetTransactionSnapshot());
+	PushActiveSnapshot(snapshot);
 
-	indexForm->indisvalid = true;
+	/*
+	 * Perform a scan of each concurrent index with the heap, then insert
+	 * any missing index entries.
+	 */
+	foreach(lc, concurrentIndexIds)
+		validate_index(heapOid, lfirst_oid(lc), snapshot);
 
-	simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
-	CatalogUpdateIndexes(pg_index, indexTuple);
+	/*
+	 * Concurrent indexes can now be marked valid -- update pg_index entries
+	 */
+	foreach(lc, concurrentIndexIds)
+		index_concurrent_mark(lfirst_oid(lc), INDEX_MARK_VALID);
 
-	heap_close(pg_index, RowExclusiveLock);
+	/*
+	 * The concurrent indexes are now valid as they contain all the tuples
+	 * necessary. However, it might not have taken into account deleted tuples
+	 * before the reference snapshot was taken, so we need to wait for the
+	 * transactions that might have older snapshots than ours.
+	 */
+	WaitForOldSnapshots(snapshot);
 
 	/*
-	 * The pg_index update will cause backends (including this one) to update
-	 * relcache entries for the index itself, but we should also send a
-	 * relcache inval on the parent table to force replanning of cached plans.
-	 * Otherwise existing sessions might fail to use the new index where it
-	 * would be useful.  (Note that our earlier commits did not create reasons
-	 * to replan; relcache flush on the index itself was sufficient.)
+	 * The pg_index update will cause backends to update its entries for the
+	 * concurrent index but it is necessary to do the same whing
 	 */
-	CacheInvalidateRelcacheByRelid(heaprelid.relId);
+	CacheInvalidateRelcacheByRelid(heapLockId.relId);
 
 	/* we can now do away with our active snapshot */
 	PopActiveSnapshot();
@@ -891,12 +1013,107 @@ DefineIndex(IndexStmt *stmt,
 	/* And we can remove the validating snapshot too */
 	UnregisterSnapshot(snapshot);
 
+	/* Commit this transaction to make the concurrent index valid */
+	CommitTransactionCommand();
+	StartTransactionCommand();
+
 	/*
-	 * Last thing to do is release the session-level lock on the parent table.
+	 * Phase 4 of REINDEX CONCURRENTLY
+	 *
+	 * Now that the concurrent indexes are valid and can be used, we need to
+	 * swap each concurrent index with its corresponding old index. The old
+	 * index is marked as invalid once this is done, making it not usable
+	 * by other transactions once this transaction is committed.
 	 */
-	UnlockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
 
-	return indexRelationId;
+	/* Take reference snapshot used to wait for older snapshots */
+	snapshot = RegisterSnapshot(GetTransactionSnapshot());
+	PushActiveSnapshot(snapshot);
+
+	/* Wait for old snapshots, like previously */
+	WaitForOldSnapshots(snapshot);
+
+	/* Get the first element is concurrent index list */
+	lc2 = list_head(concurrentIndexIds);
+
+	/* Swap and mark all the indexes involved in the relation */
+	foreach(lc, realIndexIds)
+	{
+		Oid			indOid = lfirst_oid(lc);
+		Oid			concurrentOid = lfirst_oid(lc2);
+
+		/* Move to next concurrent item */
+		lc2 = lnext(lc2);
+
+		/* Swap old index and its concurrent */
+		index_concurrent_swap(concurrentOid, indOid);
+
+		/* Mark the old index as invalid */
+		index_concurrent_mark(indOid, INDEX_MARK_NOT_VALID);
+	}
+
+	/* We can now do away with our active snapshot */
+	PopActiveSnapshot();
+
+	/* And we can remove the validating snapshot too */
+	UnregisterSnapshot(snapshot);
+
+	/*
+	 * Commit this transaction had make old index invalidation visible.
+	 */
+	CommitTransactionCommand();
+	StartTransactionCommand();
+
+	/*
+	 * Phase 5 of REINDEX CONCURRENTLY
+	 *
+	 * The old indexes need to be marked as not ready. We need also to wait for
+	 * transactions that might use them.
+	 */
+	WaitForVirtualLocks(heapLocktag);
+
+	/* Get fresh snapshot for this step */
+	PushActiveSnapshot(GetTransactionSnapshot());
+
+	/* Mark the old indexes as not ready */
+	foreach(lc, realIndexIds)
+		index_concurrent_mark(lfirst_oid(lc), INDEX_MARK_NOT_READY);
+
+	/* We can do away with our snapshot */
+	PopActiveSnapshot();
+
+	/*
+	 * Commit this transaction to make the indisready update visible.
+	 */
+	CommitTransactionCommand();
+	StartTransactionCommand();
+
+	/* Get fresh snapshot for next step */
+	PushActiveSnapshot(GetTransactionSnapshot());
+
+	/*
+	 * Phase 6 of REINDEX CONCURRENTLY
+	 *
+	 * Drop the old indexes. This needs to be done through performDeletion
+	 * or related dependencies will not be dropped for the old indexes.
+	 */
+	index_concurrent_drop(realIndexIds);
+
+	/*
+	 * Last thing to do is release the session-level lock on the parent table
+	 * and the indexes of table.
+	 */
+	UnlockRelationIdForSession(&heapLockId, ShareUpdateExclusiveLock);
+	foreach(lc, indexLocks)
+	{
+		LockRelId lockRel = * (LockRelId *) lfirst(lc);
+		UnlockRelationIdForSession(&lockRel, ShareUpdateExclusiveLock);
+	}
+
+	/* We can do away with our snapshot */
+	PopActiveSnapshot();
+
+	return true;
 }
 
 
@@ -1563,7 +1780,8 @@ ChooseRelationName(const char *name1, const char *name2,
 static char *
 ChooseIndexName(const char *tabname, Oid namespaceId,
 				List *colnames, List *exclusionOpNames,
-				bool primary, bool isconstraint)
+				bool primary, bool isconstraint,
+				bool concurrent)
 {
 	char	   *indexname;
 
@@ -1589,6 +1807,13 @@ ChooseIndexName(const char *tabname, Oid namespaceId,
 									   "key",
 									   namespaceId);
 	}
+	else if (concurrent)
+	{
+		indexname = ChooseRelationName(tabname,
+									   NULL,
+									   "cct",
+									   namespaceId);
+	}
 	else
 	{
 		indexname = ChooseRelationName(tabname,
@@ -1701,18 +1926,26 @@ ChooseIndexColumnNames(List *indexElems)
  *		Recreate a specific index.
  */
 void
-ReindexIndex(RangeVar *indexRelation)
+ReindexIndex(RangeVar *indexRelation, bool concurrent)
 {
 	Oid			indOid;
 	Oid			heapOid = InvalidOid;
 
-	/* lock level used here should match index lock reindex_index() */
-	indOid = RangeVarGetRelidExtended(indexRelation, AccessExclusiveLock,
-									  false, false,
-									  RangeVarCallbackForReindexIndex,
-									  (void *) &heapOid);
+	indOid = RangeVarGetRelidExtended(indexRelation,
+				concurrent ? ShareUpdateExclusiveLock : AccessExclusiveLock,
+				false, false,
+				RangeVarCallbackForReindexIndex,
+				(void *) &heapOid);
+
+	/* This is all for the non-concurrent case */
+	if (!concurrent)
+	{
+		reindex_index(indOid, false);
+		return;
+	}
 
-	reindex_index(indOid, false);
+	/* Continue through REINDEX CONCURRENTLY */
+	ReindexConcurrentIndexes(heapOid, list_make1_oid(indOid));
 }
 
 /*
@@ -1774,18 +2007,139 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation,
 	}
 }
 
+
+/*
+ * WaitForVirtualLocks
+ *
+ * Wait until no transaction can have the table open with the index marked as
+ * read-only for updates.
+ * To do this, inquire which xacts currently would conflict with ShareLock on
+ * the table referred by the LOCKTAG -- ie, which ones have a lock that permits
+ * writing the table. Then wait for each of these xacts to commit or abort.
+ * Note: GetLockConflicts() never reports our own xid, hence we need not
+ * check for that.	Also, prepared xacts are not reported, which is fine
+ * since they certainly aren't going to do anything more.
+ */
+static void
+WaitForVirtualLocks(LOCKTAG heaplocktag)
+{
+	VirtualTransactionId *old_lockholders;
+
+	old_lockholders = GetLockConflicts(&heaplocktag, ShareLock);
+
+	while (VirtualTransactionIdIsValid(*old_lockholders))
+	{
+		VirtualXactLock(*old_lockholders, true);
+		old_lockholders++;
+	}
+}
+
+
+/*
+ * WaitForOldSnapshots
+ *
+ * Wait for transactions that might have older snapshot than the given one,
+ * because is might not contain tuples deleted just before it has been taken.
+ * Obtain a list of VXIDs  of such transactions, and wait for them
+ * individually.
+ *
+ * We can exclude any running transactions that have xmin > the xmin of
+ * our reference snapshot; their oldest snapshot must be newer than ours.
+ * We can also exclude any transactions that have xmin = zero, since they
+ * evidently have no live snapshot at all (and any one they might be in
+ * process of taking is certainly newer than ours).  Transactions in other
+ * DBs can be ignored too, since they'll never even be able to see this
+ * index.
+ *
+ * We can also exclude autovacuum processes and processes running manual
+ * lazy VACUUMs, because they won't be fazed by missing index entries
+ * either.	(Manual ANALYZEs, however, can't be excluded because they
+ * might be within transactions that are going to do arbitrary operations
+ * later.)
+ *
+ * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not
+ * check for that.
+ *
+ * If a process goes idle-in-transaction with xmin zero, we do not need to
+ * wait for it anymore, per the above argument.  We do not have the
+ * infrastructure right now to stop waiting if that happens, but we can at
+ * least avoid the folly of waiting when it is idle at the time we would
+ * begin to wait.  We do this by repeatedly rechecking the output of
+ * GetCurrentVirtualXIDs.  If, during any iteration, a particular vxid
+ * doesn't show up in the output, we know we can forget about it.
+ */
+static void
+WaitForOldSnapshots(Snapshot snapshot)
+{
+	int			i, 	n_old_snapshots;
+	VirtualTransactionId *old_snapshots;
+
+	old_snapshots = GetCurrentVirtualXIDs(snapshot->xmin, true, false,
+										  PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
+										  &n_old_snapshots);
+
+	for (i = 0; i < n_old_snapshots; i++)
+	{
+		if (!VirtualTransactionIdIsValid(old_snapshots[i]))
+			continue;			/* found uninteresting in previous cycle */
+
+		if (i > 0)
+		{
+			/* see if anything's changed ... */
+			VirtualTransactionId *newer_snapshots;
+			int			n_newer_snapshots;
+			int			j;
+			int			k;
+
+			newer_snapshots = GetCurrentVirtualXIDs(snapshot->xmin,
+													true, false,
+										 PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
+													&n_newer_snapshots);
+			for (j = i; j < n_old_snapshots; j++)
+			{
+				if (!VirtualTransactionIdIsValid(old_snapshots[j]))
+					continue;	/* found uninteresting in previous cycle */
+				for (k = 0; k < n_newer_snapshots; k++)
+				{
+					if (VirtualTransactionIdEquals(old_snapshots[j],
+												   newer_snapshots[k]))
+						break;
+				}
+				if (k >= n_newer_snapshots)		/* not there anymore */
+					SetInvalidVirtualTransactionId(old_snapshots[j]);
+			}
+			pfree(newer_snapshots);
+		}
+
+		if (VirtualTransactionIdIsValid(old_snapshots[i]))
+			VirtualXactLock(old_snapshots[i], true);
+	}
+}
+
+
 /*
  * ReindexTable
  *		Recreate all indexes of a table (and of its toast table, if any)
  */
 void
-ReindexTable(RangeVar *relation)
+ReindexTable(RangeVar *relation, bool concurrent)
 {
 	Oid			heapOid;
 
 	/* The lock level used here should match reindex_relation(). */
-	heapOid = RangeVarGetRelidExtended(relation, ShareLock, false, false,
-									   RangeVarCallbackOwnsTable, NULL);
+	heapOid = RangeVarGetRelidExtended(relation,
+		concurrent ? ShareUpdateExclusiveLock : ShareLock,
+		false, false,
+		RangeVarCallbackOwnsTable, NULL);
+
+	/* Run through the concurrent process if necessary */
+	if (concurrent && !ReindexConcurrentIndexes(heapOid, NIL))
+	{
+		ereport(NOTICE,
+				(errmsg("table \"%s\" has no indexes",
+						relation->relname)));
+		return;
+	}
 
 	if (!reindex_relation(heapOid, REINDEX_REL_PROCESS_TOAST))
 		ereport(NOTICE,
@@ -1802,7 +2156,10 @@ ReindexTable(RangeVar *relation)
  * That means this must not be called within a user transaction block!
  */
 void
-ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
+ReindexDatabase(const char *databaseName,
+				bool do_system,
+				bool do_user,
+				bool concurrent)
 {
 	Relation	relationRelation;
 	HeapScanDesc scan;
@@ -1814,6 +2171,12 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
 
 	AssertArg(databaseName);
 
+	/* CONCURRENTLY operation is not allowed for a database */
+	if (concurrent && do_system)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("cannot reindex system concurrently")));
+
 	if (strcmp(databaseName, get_database_name(MyDatabaseId)) != 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 139b1bd..72f0178 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3602,6 +3602,7 @@ _copyReindexStmt(const ReindexStmt *from)
 	COPY_STRING_FIELD(name);
 	COPY_SCALAR_FIELD(do_system);
 	COPY_SCALAR_FIELD(do_user);
+	COPY_SCALAR_FIELD(concurrent);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index cebd030..e178928 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1900,6 +1900,7 @@ _equalReindexStmt(const ReindexStmt *a, const ReindexStmt *b)
 	COMPARE_STRING_FIELD(name);
 	COMPARE_SCALAR_FIELD(do_system);
 	COMPARE_SCALAR_FIELD(do_user);
+	COMPARE_SCALAR_FIELD(concurrent);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0d3a20d..e6ea1ba 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -6607,15 +6607,16 @@ opt_if_exists: IF_P EXISTS						{ $$ = TRUE; }
  *****************************************************************************/
 
 ReindexStmt:
-			REINDEX reindex_type qualified_name opt_force
+			REINDEX reindex_type qualified_name opt_force opt_concurrently
 				{
 					ReindexStmt *n = makeNode(ReindexStmt);
 					n->kind = $2;
 					n->relation = $3;
 					n->name = NULL;
+					n->concurrent = $5;
 					$$ = (Node *)n;
 				}
-			| REINDEX SYSTEM_P name opt_force
+			| REINDEX SYSTEM_P name opt_force opt_concurrently
 				{
 					ReindexStmt *n = makeNode(ReindexStmt);
 					n->kind = OBJECT_DATABASE;
@@ -6623,9 +6624,10 @@ ReindexStmt:
 					n->relation = NULL;
 					n->do_system = true;
 					n->do_user = false;
+					n->concurrent = $5;
 					$$ = (Node *)n;
 				}
-			| REINDEX DATABASE name opt_force
+			| REINDEX DATABASE name opt_force opt_concurrently
 				{
 					ReindexStmt *n = makeNode(ReindexStmt);
 					n->kind = OBJECT_DATABASE;
@@ -6633,6 +6635,7 @@ ReindexStmt:
 					n->relation = NULL;
 					n->do_system = true;
 					n->do_user = true;
+					n->concurrent = $5;
 					$$ = (Node *)n;
 				}
 		;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index fde2c82..3bad1b5 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1258,15 +1258,19 @@ standard_ProcessUtility(Node *parsetree,
 			{
 				ReindexStmt *stmt = (ReindexStmt *) parsetree;
 
+				if (stmt->concurrent)
+					PreventTransactionChain(isTopLevel,
+											"REINDEX CONCURRENTLY");
+
 				/* we choose to allow this during "read only" transactions */
 				PreventCommandDuringRecovery("REINDEX");
 				switch (stmt->kind)
 				{
 					case OBJECT_INDEX:
-						ReindexIndex(stmt->relation);
+						ReindexIndex(stmt->relation, stmt->concurrent);
 						break;
 					case OBJECT_TABLE:
-						ReindexTable(stmt->relation);
+						ReindexTable(stmt->relation, stmt->concurrent);
 						break;
 					case OBJECT_DATABASE:
 
@@ -1278,8 +1282,8 @@ standard_ProcessUtility(Node *parsetree,
 						 */
 						PreventTransactionChain(isTopLevel,
 												"REINDEX DATABASE");
-						ReindexDatabase(stmt->name,
-										stmt->do_system, stmt->do_user);
+						ReindexDatabase(stmt->name, stmt->do_system,
+										stmt->do_user, stmt->concurrent);
 						break;
 					default:
 						elog(ERROR, "unrecognized object type: %d",
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index eb417ce..5410a6c 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -19,6 +19,15 @@
 
 #define DEFAULT_INDEX_TYPE	"btree"
 
+typedef enum IndexMarkOperation
+{
+	INDEX_MARK_VALID,
+	INDEX_MARK_NOT_VALID,
+	INDEX_MARK_READY,
+	INDEX_MARK_NOT_READY
+} IndexMarkOperation;
+
+
 /* Typedef for callback function for IndexBuildHeapScan */
 typedef void (*IndexBuildCallback) (Relation index,
 												HeapTuple htup,
@@ -52,6 +61,20 @@ extern Oid index_create(Relation heapRelation,
 			 bool skip_build,
 			 bool concurrent);
 
+extern Oid index_concurrent_create(Relation heapRelation,
+								   Oid indOid,
+								   char *concurrentName);
+
+extern void index_concurrent_build(Oid heapOid,
+								   Oid indexOid,
+								   bool isprimary);
+
+extern void index_concurrent_mark(Oid indOid, IndexMarkOperation operation);
+
+extern void index_concurrent_swap(Oid indexOid1, Oid indexOid2);
+
+extern void index_concurrent_drop(List *IndexIds);
+
 extern void index_constraint_create(Relation heapRelation,
 						Oid indexRelationId,
 						IndexInfo *indexInfo,
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 300f7ea..7cfe94d 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -26,10 +26,11 @@ extern Oid DefineIndex(IndexStmt *stmt,
 			bool check_rights,
 			bool skip_build,
 			bool quiet);
-extern void ReindexIndex(RangeVar *indexRelation);
-extern void ReindexTable(RangeVar *relation);
+extern void ReindexIndex(RangeVar *indexRelation, bool concurrent);
+extern void ReindexTable(RangeVar *relation, bool concurrent);
 extern void ReindexDatabase(const char *databaseName,
-				bool do_system, bool do_user);
+							bool do_system, bool do_user, bool concurrent);
+extern bool ReindexConcurrentIndexes(Oid heapOid, List *indexIds);
 extern char *makeObjectName(const char *name1, const char *name2,
 			   const char *label);
 extern char *ChooseRelationName(const char *name1, const char *name2,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 4fe644e..a4000d3 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2510,6 +2510,7 @@ typedef struct ReindexStmt
 	const char *name;			/* name of database to reindex */
 	bool		do_system;		/* include system tables in database case */
 	bool		do_user;		/* include user tables in database case */
+	bool		concurrent;		/* reindex concurrently? */
 } ReindexStmt;
 
 /* ----------------------
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 2ae991e..d64c9b6 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2721,3 +2721,41 @@ ORDER BY thousand;
         1 |     1001
 (2 rows)
 
+--
+-- Check behavior of REINDEX and REINDEX CONCURRENTLY
+--
+CREATE TABLE concur_reindex_tab (c1 int, c2 text);
+-- REINDEX
+REINDEX TABLE concur_reindex_tab; -- notice
+REINDEX TABLE concur_reindex_tab CONCURRENTLY; -- notice
+NOTICE:  table "concur_reindex_tab" has no indexes
+CREATE INDEX concur_reindex_tab1 ON concur_reindex_tab(c1);
+CREATE INDEX concur_reindex_tab2 ON concur_reindex_tab(c2);
+INSERT INTO concur_reindex_tab VALUES  (1,'a');
+INSERT INTO concur_reindex_tab VALUES  (2,'a');
+REINDEX INDEX concur_reindex_tab1 CONCURRENTLY;
+REINDEX TABLE concur_reindex_tab CONCURRENTLY;
+-- Check errors
+-- Cannot run inside a transaction block
+BEGIN;
+REINDEX TABLE concur_reindex_tab CONCURRENTLY;
+ERROR:  REINDEX CONCURRENTLY cannot run inside a transaction block
+COMMIT;
+REINDEX TABLE pg_database CONCURRENTLY;-- no shared relation
+ERROR:  concurrent reindex is not supported for shared relations
+REINDEX DATABASE postgres CONCURRENTLY; -- not allowed for DATABASE
+ERROR:  cannot reindex system concurrently
+REINDEX SYSTEM postgres CONCURRENTLY; -- not allowed for SYSTEM
+ERROR:  cannot reindex system concurrently
+-- Check the relation status, there should not be invalid indexes
+\d concur_reindex_tab
+Table "public.concur_reindex_tab"
+ Column |  Type   | Modifiers 
+--------+---------+-----------
+ c1     | integer | 
+ c2     | text    | 
+Indexes:
+    "concur_reindex_tab1" btree (c1)
+    "concur_reindex_tab2" btree (c2)
+
+DROP TABLE concur_reindex_tab;
diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql
index 914e7a5..7b3b036 100644
--- a/src/test/regress/sql/create_index.sql
+++ b/src/test/regress/sql/create_index.sql
@@ -912,3 +912,30 @@ ORDER BY thousand;
 SELECT thousand, tenthous FROM tenk1
 WHERE thousand < 2 AND tenthous IN (1001,3000)
 ORDER BY thousand;
+
+--
+-- Check behavior of REINDEX and REINDEX CONCURRENTLY
+--
+CREATE TABLE concur_reindex_tab (c1 int, c2 text);
+-- REINDEX
+REINDEX TABLE concur_reindex_tab; -- notice
+REINDEX TABLE concur_reindex_tab CONCURRENTLY; -- notice
+CREATE INDEX concur_reindex_tab1 ON concur_reindex_tab(c1);
+CREATE INDEX concur_reindex_tab2 ON concur_reindex_tab(c2);
+INSERT INTO concur_reindex_tab VALUES  (1,'a');
+INSERT INTO concur_reindex_tab VALUES  (2,'a');
+REINDEX INDEX concur_reindex_tab1 CONCURRENTLY;
+REINDEX TABLE concur_reindex_tab CONCURRENTLY;
+
+-- Check errors
+-- Cannot run inside a transaction block
+BEGIN;
+REINDEX TABLE concur_reindex_tab CONCURRENTLY;
+COMMIT;
+REINDEX TABLE pg_database CONCURRENTLY;-- no shared relation
+REINDEX DATABASE postgres CONCURRENTLY; -- not allowed for DATABASE
+REINDEX SYSTEM postgres CONCURRENTLY; -- not allowed for SYSTEM
+
+-- Check the relation status, there should not be invalid indexes
+\d concur_reindex_tab
+DROP TABLE concur_reindex_tab;