/* * GetNewOid * Generate a new OID that is unique within the given relation. * * Caller must have a suitable lock on the relation. * * Uniqueness is promised only if the relation has a unique index on OID. * This is true for all system catalogs that have OIDs, but might not be * true for user tables. Note that we are effectively assuming that the * table has a relatively small number of entries (much less than 2^32) * and there aren't very long runs of consecutive existing OIDs. Again, * this is reasonable for system catalogs but less so for user tables. * * Since the OID is not immediately inserted into the table, there is a * race condition here; but a problem could occur only if someone else * managed to cycle through 2^32 OIDs and generate the same OID before we * finish inserting our row. This seems unlikely to be a problem. Note * that if we had to *commit* the row to end the race condition, the risk * would be rather higher; therefore we use SnapshotDirty in the test, * so that we will see uncommitted rows. */ Oid GetNewOid(Relation relation) { Oid oidIndex; /* If relation doesn't have OIDs at all, caller is confused */ Assert(relation->rd_rel->relhasoids); /* In bootstrap mode, we don't have any indexes to use */ if (IsBootstrapProcessingMode()) return GetNewObjectId(); /* The relcache will cache the identity of the OID index for us */ oidIndex = RelationGetOidIndex(relation); /* If no OID index, just hand back the next OID counter value */ if (!OidIsValid(oidIndex)) { /* * System catalogs that have OIDs should *always* have a unique OID * index; we should only take this path for user tables. Give a * warning if it looks like somebody forgot an index. */ if (IsSystemRelation(relation)) elog(WARNING, "generating possibly-non-unique OID for \"%s\"", RelationGetRelationName(relation)); return GetNewObjectId(); } /* Otherwise, use the index to find a nonconflicting OID */ return GetNewOidWithIndex(relation, oidIndex, ObjectIdAttributeNumber); }
/* * GetNewOid * Generate a new OID that is unique within the given relation. * * Caller must have a suitable lock on the relation. * * Uniqueness is promised only if the relation has a unique index on OID. * This is true for all system catalogs that have OIDs, but might not be * true for user tables. Note that we are effectively assuming that the * table has a relatively small number of entries (much less than 2^32) * and there aren't very long runs of consecutive existing OIDs. Again, * this is reasonable for system catalogs but less so for user tables. * * Since the OID is not immediately inserted into the table, there is a * race condition here; but a problem could occur only if someone else * managed to cycle through 2^32 OIDs and generate the same OID before we * finish inserting our row. This seems unlikely to be a problem. Note * that if we had to *commit* the row to end the race condition, the risk * would be rather higher; therefore we use SnapshotDirty in the test, * so that we will see uncommitted rows. */ Oid GetNewOid(Relation relation) { Oid newOid; Oid oidIndex; Relation indexrel; /* If relation doesn't have OIDs at all, caller is confused */ Assert(relation->rd_rel->relhasoids); /* In bootstrap mode, we don't have any indexes to use */ if (IsBootstrapProcessingMode()) return GetNewObjectId(); /* The relcache will cache the identity of the OID index for us */ oidIndex = RelationGetOidIndex(relation); /* If no OID index, just hand back the next OID counter value */ if (!OidIsValid(oidIndex)) { Oid result; /* * System catalogs that have OIDs should *always* have a unique OID * index; we should only take this path for user tables. Give a * warning if it looks like somebody forgot an index. */ if (IsSystemRelation(relation)) elog(WARNING, "generating possibly-non-unique OID for \"%s\"", RelationGetRelationName(relation)); result= GetNewObjectId(); if (IsSystemNamespace(RelationGetNamespace(relation))) { if (Gp_role == GP_ROLE_EXECUTE) { elog(DEBUG1,"Allocating Oid %u on relid %u %s in EXECUTE mode",result,relation->rd_id,RelationGetRelationName(relation)); } if (Gp_role == GP_ROLE_DISPATCH) { elog(DEBUG5,"Allocating Oid %u on relid %u %s in DISPATCH mode",result,relation->rd_id,RelationGetRelationName(relation)); } } return result; } /* Otherwise, use the index to find a nonconflicting OID */ indexrel = index_open(oidIndex, AccessShareLock); newOid = GetNewOidWithIndex(relation, indexrel); index_close(indexrel, AccessShareLock); return newOid; }
/* * GetNewOid * Generate a new OID that is unique within the given relation. * * Caller must have a suitable lock on the relation. * * Uniqueness is promised only if the relation has a unique index on OID. * This is true for all system catalogs that have OIDs, but might not be * true for user tables. Note that we are effectively assuming that the * table has a relatively small number of entries (much less than 2^32) * and there aren't very long runs of consecutive existing OIDs. Again, * this is reasonable for system catalogs but less so for user tables. * * Since the OID is not immediately inserted into the table, there is a * race condition here; but a problem could occur only if someone else * managed to cycle through 2^32 OIDs and generate the same OID before we * finish inserting our row. This seems unlikely to be a problem. Note * that if we had to *commit* the row to end the race condition, the risk * would be rather higher; therefore we use SnapshotDirty in the test, * so that we will see uncommitted rows. */ Oid GetNewOid(Relation relation) { Oid newOid; Oid oidIndex; Relation indexrel; /* If relation doesn't have OIDs at all, caller is confused */ Assert(relation->rd_rel->relhasoids); /* In bootstrap mode, we don't have any indexes to use */ if (IsBootstrapProcessingMode()) return GetNewObjectId(); /* The relcache will cache the identity of the OID index for us */ oidIndex = RelationGetOidIndex(relation); /* If no OID index, just hand back the next OID counter value */ if (!OidIsValid(oidIndex)) { /* * System catalogs that have OIDs should *always* have a unique OID * index; we should only take this path for user tables. Give a * warning if it looks like somebody forgot an index. */ if (IsSystemRelation(relation)) elog(WARNING, "generating possibly-non-unique OID for \"%s\"", RelationGetRelationName(relation)); return GetNewObjectId(); } /* Otherwise, use the index to find a nonconflicting OID */ indexrel = index_open(oidIndex, AccessShareLock); do { newOid = GetNewOidWithIndex(relation, indexrel); } while(!IsOidAcceptable(newOid)); index_close(indexrel, AccessShareLock); /* * Most catalog objects need to have the same OID in the master and all * segments. When creating a new object, the master should allocate the * OID and tell the segments to use the same, so segments should have no * need to ever allocate OIDs on their own. Therefore, give a WARNING if * GetNewOid() is called in a segment. (There are a few exceptions, see * RelationNeedsSynchronizedOIDs()). */ if (Gp_role == GP_ROLE_EXECUTE && RelationNeedsSynchronizedOIDs(relation)) elog(PANIC, "allocated OID %u for relation \"%s\" in segment", newOid, RelationGetRelationName(relation)); return newOid; }
void cdb_sync_oid_to_segments(void) { if (Gp_role == GP_ROLE_DISPATCH && IsNormalProcessingMode()) { Oid max_oid = get_max_oid_from_segDBs(); /* Move our oid counter ahead of QEs */ while(GetNewObjectId() <= max_oid); /* Burn a few extra just for safety */ for (int i = 0; i < 10; i++) GetNewObjectId(); } }
/* * GetNewOidWithIndex * Guts of GetNewOid: use the supplied index * * This is exported separately because there are cases where we want to use * an index that will not be recognized by RelationGetOidIndex: TOAST tables * have indexes that are usable, but have multiple columns and are on * ordinary columns rather than a true OID column. This code will work * anyway, so long as the OID is the index's first column. The caller must * pass in the actual heap attnum of the OID column, however. * * Caller must have a suitable lock on the relation. */ Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn) { Oid newOid; SnapshotData SnapshotDirty; SysScanDesc scan; ScanKeyData key; bool collides; InitDirtySnapshot(SnapshotDirty); /* Generate new OIDs until we find one not in the table */ do { CHECK_FOR_INTERRUPTS(); newOid = GetNewObjectId(); ScanKeyInit(&key, oidcolumn, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(newOid)); /* see notes above about using SnapshotDirty */ scan = systable_beginscan(relation, indexId, true, &SnapshotDirty, 1, &key); collides = HeapTupleIsValid(systable_getnext(scan)); systable_endscan(scan); } while (collides); return newOid; }
/* * GetNewOidWithIndex * Guts of GetNewOid: use the supplied index * * This is exported separately because there are cases where we want to use * an index that will not be recognized by RelationGetOidIndex: TOAST tables * and pg_largeobject have indexes that are usable, but have multiple columns * and are on ordinary columns rather than a true OID column. This code * will work anyway, so long as the OID is the index's first column. * * Caller must have a suitable lock on the relation. */ Oid GetNewOidWithIndex(Relation relation, Relation indexrel) { Oid newOid; SnapshotData SnapshotDirty; IndexScanDesc scan; ScanKeyData key; bool collides; InitDirtySnapshot(SnapshotDirty); /* Generate new OIDs until we find one not in the table */ do { CHECK_FOR_INTERRUPTS(); newOid = GetNewObjectId(); ScanKeyInit(&key, (AttrNumber) 1, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(newOid)); /* see notes above about using SnapshotDirty */ scan = index_beginscan(relation, indexrel, &SnapshotDirty, 1, &key); collides = HeapTupleIsValid(index_getnext(scan, ForwardScanDirection)); index_endscan(scan); } while (collides); return newOid; }
/* * Can the given OID be used as pg_class.relfilenode? * * As a side-effect, advances OID counter to the given OID and remembers * that the OID has been used as a relfilenode, so that the same value * doesn't get chosen again. */ bool CheckNewRelFileNodeIsOk(Oid newOid, Oid reltablespace, bool relisshared) { RelFileNode rnode; char *rpath; int fd; bool collides; SnapshotData SnapshotDirty; /* * Advance our current OID counter with the given value, to keep * the counter roughly in sync across all nodes. This ensures * that a GetNewRelFileNode() call after this will not choose the * same OID, and won't have to loop excessively to retry. That * still leaves a race condition, if GetNewRelFileNode() is called * just before CheckNewRelFileNodeIsOk() - UseOidForRelFileNode() * is called to plug that. * * FIXME: handle OID wraparound gracefully. */ while(GetNewObjectId() < newOid); if (!UseOidForRelFileNode(newOid)) return false; InitDirtySnapshot(SnapshotDirty); /* This should match RelationInitPhysicalAddr */ rnode.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace; rnode.dbNode = relisshared ? InvalidOid : MyDatabaseId; rnode.relNode = newOid; /* Check for existing file of same name */ rpath = relpath(rnode); fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0); if (fd >= 0) { /* definite collision */ gp_retry_close(fd); collides = true; } else collides = false; pfree(rpath); elog(DEBUG1, "Called CheckNewRelFileNodeIsOk in %s mode for %u / %u / %u. " "collides = %s", (Gp_role == GP_ROLE_EXECUTE ? "execute" : Gp_role == GP_ROLE_UTILITY ? "utility" : "dispatch"), newOid, reltablespace, relisshared, collides ? "true" : "false"); return !collides; }
_tsTraceClassExt::_tsTraceClassExt(const _tsTraceInfoExt &info) : m_TraceInfo(info), m_classInstance(GetNewObjectId()) { if (m_TraceInfo.enabled) { LOG(CallTrace, "CREATE " << m_TraceInfo.name << " [" << ToHex()(this) << " - " << m_classInstance << "]"); } }
/* * GetNewRelFileNode * Generate a new relfilenode number that is unique within the given * tablespace. * * If the relfilenode will also be used as the relation's OID, pass the * opened pg_class catalog, and this routine will guarantee that the result * is also an unused OID within pg_class. If the result is to be used only * as a relfilenode for an existing relation, pass NULL for pg_class. * * As with GetNewOid, there is some theoretical risk of a race condition, * but it doesn't seem worth worrying about. * * Note: we don't support using this in bootstrap mode. All relations * created by bootstrap have preassigned OIDs, so there's no need. */ Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class) { RelFileNode rnode; char *rpath; int fd; bool collides; /* This logic should match RelationInitPhysicalAddr */ rnode.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace; rnode.dbNode = (rnode.spcNode == GLOBALTABLESPACE_OID) ? InvalidOid : MyDatabaseId; do { CHECK_FOR_INTERRUPTS(); /* Generate the OID */ if (pg_class) rnode.relNode = GetNewOid(pg_class); else rnode.relNode = GetNewObjectId(); /* Check for existing file of same name */ rpath = relpath(rnode, MAIN_FORKNUM); fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0); if (fd >= 0) { /* definite collision */ close(fd); collides = true; } else { /* * Here we have a little bit of a dilemma: if errno is something * other than ENOENT, should we declare a collision and loop? In * particular one might think this advisable for, say, EPERM. * However there really shouldn't be any unreadable files in a * tablespace directory, and if the EPERM is actually complaining * that we can't read the directory itself, we'd be in an infinite * loop. In practice it seems best to go ahead regardless of the * errno. If there is a colliding file we will get an smgr * failure when we attempt to create the new relation file. */ collides = false; } pfree(rpath); } while (collides); return rnode.relNode; }
void cdb_sync_oid_to_segments(void) { if (Gp_role == GP_ROLE_DISPATCH && IsNormalProcessingMode()) { int i; /* Burn a few extra just for safety */ for (i=0;i<10;i++) GetNewObjectId(); } }
/* * GetNewOidWithIndex * Guts of GetNewOid: use the supplied index * * This is exported separately because there are cases where we want to use * an index that will not be recognized by RelationGetOidIndex: TOAST tables * and pg_largeobject have indexes that are usable, but have multiple columns * and are on ordinary columns rather than a true OID column. This code * will work anyway, so long as the OID is the index's first column. * * Caller must have a suitable lock on the relation. */ Oid GetNewOidWithIndex(Relation relation, Relation indexrel) { Oid newOid; IndexScanDesc scan; ScanKeyData key; bool collides; /* Generate new OIDs until we find one not in the table */ do { CHECK_FOR_INTERRUPTS(); newOid = GetNewObjectId(); ScanKeyInit(&key, (AttrNumber) 1, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(newOid)); /* see notes above about using SnapshotDirty */ scan = index_beginscan(relation, indexrel, SnapshotDirty, 1, &key); collides = HeapTupleIsValid(index_getnext(scan, ForwardScanDirection)); index_endscan(scan); } while (collides); if (IsSystemNamespace(RelationGetNamespace(relation))) { if (Gp_role == GP_ROLE_EXECUTE) { if (relation->rd_id != 2604 /* pg_attrdef */ && relation->rd_id != 2606 /* pg_constraint */ && relation->rd_id != 2615 /* pg_namespace */) elog(DEBUG1,"Allocating Oid %u with index on relid %u %s in EXECUTE mode",newOid,relation->rd_id, RelationGetRelationName(relation)); else elog(DEBUG4,"Allocating Oid %u with index on relid %u %s in EXECUTE mode",newOid,relation->rd_id, RelationGetRelationName(relation)); } if (Gp_role == GP_ROLE_DISPATCH) { elog(DEBUG5,"Allocating Oid %u with index on relid %u %s in DISPATCH mode",newOid,relation->rd_id, RelationGetRelationName(relation)); } } return newOid; }
/* * GetNewOidWithIndex * Guts of GetNewOid: use the supplied index * * This is exported separately because there are cases where we want to use * an index that will not be recognized by RelationGetOidIndex: TOAST tables * have indexes that are usable, but have multiple columns and are on * ordinary columns rather than a true OID column. This code will work * anyway, so long as the OID is the index's first column. The caller must * pass in the actual heap attnum of the OID column, however. * * Caller must have a suitable lock on the relation. */ Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn) { Oid newOid; SysScanDesc scan; ScanKeyData key; bool collides; /* * We should never be asked to generate a new pg_type OID during * pg_upgrade; doing so would risk collisions with the OIDs it wants to * assign. Hitting this assert means there's some path where we failed to * ensure that a type OID is determined by commands in the dump script. */ Assert(!IsBinaryUpgrade || RelationGetRelid(relation) != TypeRelationId); /* Generate new OIDs until we find one not in the table */ do { CHECK_FOR_INTERRUPTS(); newOid = GetNewObjectId(); ScanKeyInit(&key, oidcolumn, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(newOid)); /* see notes above about using SnapshotAny */ scan = systable_beginscan(relation, indexId, true, SnapshotAny, 1, &key); collides = HeapTupleIsValid(systable_getnext(scan)); systable_endscan(scan); } while (collides); return newOid; }
/* * GetNewRelFileNode * Generate a new relfilenode number that is unique within the given * tablespace. * * If the relfilenode will also be used as the relation's OID, pass the * opened pg_class catalog, and this routine will guarantee that the result * is also an unused OID within pg_class. If the result is to be used only * as a relfilenode for an existing relation, pass NULL for pg_class. * * As with GetNewOid, there is some theoretical risk of a race condition, * but it doesn't seem worth worrying about. * * Note: we don't support using this in bootstrap mode. All relations * created by bootstrap have preassigned OIDs, so there's no need. */ Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence) { RelFileNodeBackend rnode; char *rpath; int fd; bool collides; BackendId backend; switch (relpersistence) { case RELPERSISTENCE_TEMP: backend = MyBackendId; break; case RELPERSISTENCE_UNLOGGED: case RELPERSISTENCE_PERMANENT: backend = InvalidBackendId; break; default: elog(ERROR, "invalid relpersistence: %c", relpersistence); return InvalidOid; /* placate compiler */ } /* This logic should match RelationInitPhysicalAddr */ rnode.node.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace; rnode.node.dbNode = (rnode.node.spcNode == GLOBALTABLESPACE_OID) ? InvalidOid : MyDatabaseId; /* * The relpath will vary based on the backend ID, so we must initialize * that properly here to make sure that any collisions based on filename * are properly detected. */ rnode.backend = backend; do { CHECK_FOR_INTERRUPTS(); /* Generate the OID */ if (pg_class) rnode.node.relNode = GetNewOid(pg_class); else rnode.node.relNode = GetNewObjectId(); /* Check for existing file of same name */ rpath = relpath(rnode, MAIN_FORKNUM); fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0); if (fd >= 0) { /* definite collision */ close(fd); collides = true; } else { /* * Here we have a little bit of a dilemma: if errno is something * other than ENOENT, should we declare a collision and loop? In * particular one might think this advisable for, say, EPERM. * However there really shouldn't be any unreadable files in a * tablespace directory, and if the EPERM is actually complaining * that we can't read the directory itself, we'd be in an infinite * loop. In practice it seems best to go ahead regardless of the * errno. If there is a colliding file we will get an smgr * failure when we attempt to create the new relation file. */ collides = false; } pfree(rpath); } while (collides); return rnode.node.relNode; }
/* * GetNewRelFileNode * Generate a new relfilenode number that is unique within the given * tablespace. * * If the relfilenode will also be used as the relation's OID, pass the * opened pg_class catalog, and this routine will guarantee that the result * is also an unused OID within pg_class. If the result is to be used only * as a relfilenode for an existing relation, pass NULL for pg_class. * * As with GetNewOid, there is some theoretical risk of a race condition, * but it doesn't seem worth worrying about. * * Note: we don't support using this in bootstrap mode. All relations * created by bootstrap have preassigned OIDs, so there's no need. */ Oid GetNewRelFileNode(Oid reltablespace, bool relisshared, Relation pg_class) { RelFileNode rnode; char *rpath; int fd; bool collides = true; /* This should match RelationInitPhysicalAddr */ rnode.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace; rnode.dbNode = relisshared ? InvalidOid : MyDatabaseId; do { CHECK_FOR_INTERRUPTS(); /* Generate the OID */ if (pg_class) rnode.relNode = GetNewOid(pg_class); else rnode.relNode = GetNewObjectId(); if (!UseOidForRelFileNode(rnode.relNode)) continue; /* Check for existing file of same name */ rpath = relpath(rnode); fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0); if (fd >= 0) { /* definite collision */ gp_retry_close(fd); collides = true; } else { /* * Here we have a little bit of a dilemma: if errno is something * other than ENOENT, should we declare a collision and loop? In * particular one might think this advisable for, say, EPERM. * However there really shouldn't be any unreadable files in a * tablespace directory, and if the EPERM is actually complaining * that we can't read the directory itself, we'd be in an infinite * loop. In practice it seems best to go ahead regardless of the * errno. If there is a colliding file we will get an smgr * failure when we attempt to create the new relation file. */ collides = false; } pfree(rpath); } while (collides); if (Gp_role == GP_ROLE_EXECUTE) Insist(!PointerIsValid(pg_class)); elog(DEBUG1, "Calling GetNewRelFileNode in %s mode %s pg_class. New relOid = %d", (Gp_role == GP_ROLE_EXECUTE ? "execute" : Gp_role == GP_ROLE_UTILITY ? "utility" : "dispatch"), pg_class ? "with" : "without", rnode.relNode); return rnode.relNode; }
bool CheckNewRelFileNodeIsOk(Oid newOid, Oid reltablespace, bool relisshared, Relation pg_class) { RelFileNode rnode; char *rpath; int fd; bool collides; if (pg_class) { Oid oidIndex; Relation indexrel; IndexScanDesc scan; ScanKeyData key; Assert(!IsBootstrapProcessingMode()); Assert(pg_class->rd_rel->relhasoids); /* The relcache will cache the identity of the OID index for us */ oidIndex = RelationGetOidIndex(pg_class); Assert(OidIsValid(oidIndex)); indexrel = index_open(oidIndex, AccessShareLock); ScanKeyInit(&key, (AttrNumber) 1, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(newOid)); scan = index_beginscan(pg_class, indexrel, SnapshotDirty, 1, &key); collides = HeapTupleIsValid(index_getnext(scan, ForwardScanDirection)); index_endscan(scan); index_close(indexrel, AccessShareLock); if (collides) elog(ERROR, "relfilenode %d already in use in \"pg_class\"", newOid); } /* This should match RelationInitPhysicalAddr */ rnode.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace; rnode.dbNode = relisshared ? InvalidOid : MyDatabaseId; rnode.relNode = newOid; /* Check for existing file of same name */ rpath = relpath(rnode); fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0); if (fd >= 0) { /* definite collision */ gp_retry_close(fd); collides = true; } else collides = false; pfree(rpath); if (collides && !relisshared) elog(ERROR, "oid %d already in use", newOid); while(GetNewObjectId() < newOid); return !collides; }
/* * newoid - returns a unique identifier across all catalogs. * * Object Id allocation is now done by GetNewObjectID in * access/transam/varsup. * * This code probably needs to change to generate OIDs separately * for each table. */ Oid newoid(void) { return GetNewObjectId(); }