📄 tablespace.c
字号:
/* This check is just to deliver a friendlier error message */ if (!directory_is_empty(subfile)) { FreeDir(dirdesc); return false; } /* Do the real deed */ if (rmdir(subfile) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not delete directory \"%s\": %m", subfile))); pfree(subfile); } FreeDir(dirdesc); /* * Okay, try to unlink PG_VERSION (we allow it to not be there, even in * non-REDO case, for robustness). */ subfile = palloc(strlen(location) + 11 + 1); sprintf(subfile, "%s/PG_VERSION", location); if (unlink(subfile) < 0) { if (errno != ENOENT) ereport(ERROR, (errcode_for_file_access(), errmsg("could not remove file \"%s\": %m", subfile))); } pfree(subfile); /* * Okay, try to remove the symlink. We must however deal with the * possibility that it's a directory instead of a symlink --- this could * happen during WAL replay (see TablespaceCreateDbspace), and it is also * the normal case on Windows. */ if (lstat(location, &st) == 0 && S_ISDIR(st.st_mode)) { if (rmdir(location) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not remove directory \"%s\": %m", location))); } else { if (unlink(location) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not remove symbolic link \"%s\": %m", location))); } pfree(location); return true;}/* * write out the PG_VERSION file in the specified directory */static voidset_short_version(const char *path){ char *short_version; bool gotdot = false; int end; char *fullname; FILE *version_file; /* Construct short version string (should match initdb.c) */ short_version = pstrdup(PG_VERSION); for (end = 0; short_version[end] != '\0'; end++) { if (short_version[end] == '.') { Assert(end != 0); if (gotdot) break; else gotdot = true; } else if (short_version[end] < '0' || short_version[end] > '9') { /* gone past digits and dots */ break; } } Assert(end > 0 && short_version[end - 1] != '.' && gotdot); short_version[end] = '\0'; /* Now write the file */ fullname = palloc(strlen(path) + 11 + 1); sprintf(fullname, "%s/PG_VERSION", path); version_file = AllocateFile(fullname, PG_BINARY_W); if (version_file == NULL) ereport(ERROR, (errcode_for_file_access(), errmsg("could not write to file \"%s\": %m", fullname))); fprintf(version_file, "%s\n", short_version); if (FreeFile(version_file)) ereport(ERROR, (errcode_for_file_access(), errmsg("could not write to file \"%s\": %m", fullname))); pfree(fullname); pfree(short_version);}/* * Check if a directory is empty. * * This probably belongs somewhere else, but not sure where... */booldirectory_is_empty(const char *path){ DIR *dirdesc; struct dirent *de; dirdesc = AllocateDir(path); while ((de = ReadDir(dirdesc, path)) != NULL) { if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue; FreeDir(dirdesc); return false; } FreeDir(dirdesc); return true;}/* * Rename a tablespace */voidRenameTableSpace(const char *oldname, const char *newname){ Relation rel; ScanKeyData entry[1]; HeapScanDesc scan; HeapTuple tup; HeapTuple newtuple; Form_pg_tablespace newform; /* Search pg_tablespace */ rel = heap_open(TableSpaceRelationId, RowExclusiveLock); ScanKeyInit(&entry[0], Anum_pg_tablespace_spcname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(oldname)); scan = heap_beginscan(rel, SnapshotNow, 1, entry); tup = heap_getnext(scan, ForwardScanDirection); if (!HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", oldname))); newtuple = heap_copytuple(tup); newform = (Form_pg_tablespace) GETSTRUCT(newtuple); heap_endscan(scan); /* Must be owner */ if (!pg_tablespace_ownercheck(HeapTupleGetOid(newtuple), GetUserId())) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, oldname); /* Validate new name */ if (!allowSystemTableMods && IsReservedName(newname)) ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("unacceptable tablespace name \"%s\"", newname), errdetail("The prefix \"pg_\" is reserved for system tablespaces."))); /* Make sure the new name doesn't exist */ ScanKeyInit(&entry[0], Anum_pg_tablespace_spcname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(newname)); scan = heap_beginscan(rel, SnapshotNow, 1, entry); tup = heap_getnext(scan, ForwardScanDirection); if (HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("tablespace \"%s\" already exists", newname))); heap_endscan(scan); /* OK, update the entry */ namestrcpy(&(newform->spcname), newname); simple_heap_update(rel, &newtuple->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); heap_close(rel, NoLock);}/* * Change tablespace owner */voidAlterTableSpaceOwner(const char *name, Oid newOwnerId){ Relation rel; ScanKeyData entry[1]; HeapScanDesc scandesc; Form_pg_tablespace spcForm; HeapTuple tup; /* Search pg_tablespace */ rel = heap_open(TableSpaceRelationId, RowExclusiveLock); ScanKeyInit(&entry[0], Anum_pg_tablespace_spcname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(name)); scandesc = heap_beginscan(rel, SnapshotNow, 1, entry); tup = heap_getnext(scandesc, ForwardScanDirection); if (!HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", name))); spcForm = (Form_pg_tablespace) GETSTRUCT(tup); /* * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ if (spcForm->spcowner != newOwnerId) { Datum repl_val[Natts_pg_tablespace]; char repl_null[Natts_pg_tablespace]; char repl_repl[Natts_pg_tablespace]; Acl *newAcl; Datum aclDatum; bool isNull; HeapTuple newtuple; /* Otherwise, must be owner of the existing object */ if (!pg_tablespace_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, name); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); /* * Normally we would also check for create permissions here, but there * are none for tablespaces so we follow what rename tablespace does * and omit the create permissions check. * * NOTE: Only superusers may create tablespaces to begin with and so * initially only a superuser would be able to change its ownership * anyway. */ memset(repl_null, ' ', sizeof(repl_null)); memset(repl_repl, ' ', sizeof(repl_repl)); repl_repl[Anum_pg_tablespace_spcowner - 1] = 'r'; repl_val[Anum_pg_tablespace_spcowner - 1] = ObjectIdGetDatum(newOwnerId); /* * Determine the modified ACL for the new owner. This is only * necessary when the ACL is non-null. */ aclDatum = heap_getattr(tup, Anum_pg_tablespace_spcacl, RelationGetDescr(rel), &isNull); if (!isNull) { newAcl = aclnewowner(DatumGetAclP(aclDatum), spcForm->spcowner, newOwnerId); repl_repl[Anum_pg_tablespace_spcacl - 1] = 'r'; repl_val[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(newAcl); } newtuple = heap_modifytuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl); simple_heap_update(rel, &newtuple->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); heap_freetuple(newtuple); /* Update owner dependency reference */ changeDependencyOnOwner(TableSpaceRelationId, HeapTupleGetOid(tup), newOwnerId); } heap_endscan(scandesc); heap_close(rel, NoLock);}/* * Routines for handling the GUC variable 'default_tablespace'. *//* assign_hook: validate new default_tablespace, do extra actions as needed */const char *assign_default_tablespace(const char *newval, bool doit, GucSource source){ /* * If we aren't inside a transaction, we cannot do database access so * cannot verify the name. Must accept the value on faith. */ if (IsTransactionState()) { if (newval[0] != '\0' && !OidIsValid(get_tablespace_oid(newval))) { if (source >= PGC_S_INTERACTIVE) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", newval))); return NULL; } } return newval;}/* * GetDefaultTablespace -- get the OID of the current default tablespace * * May return InvalidOid to indicate "use the database's default tablespace" * * This exists to hide (and possibly optimize the use of) the * default_tablespace GUC variable. */OidGetDefaultTablespace(void){ Oid result; /* Fast path for default_tablespace == "" */ if (default_tablespace == NULL || default_tablespace[0] == '\0') return InvalidOid; /* * It is tempting to cache this lookup for more speed, but then we would * fail to detect the case where the tablespace was dropped since the GUC * variable was set. Note also that we don't complain if the value fails * to refer to an existing tablespace; we just silently return InvalidOid, * causing the new object to be created in the database's tablespace. */ result = get_tablespace_oid(default_tablespace); /* * Allow explicit specification of database's default tablespace in * default_tablespace without triggering permissions checks. */ if (result == MyDatabaseTableSpace) result = InvalidOid; return result;}/* * get_tablespace_oid - given a tablespace name, look up the OID * * Returns InvalidOid if tablespace name not found. */Oidget_tablespace_oid(const char *tablespacename){ Oid result; Relation rel; HeapScanDesc scandesc; HeapTuple tuple; ScanKeyData entry[1]; /* Search pg_tablespace */ rel = heap_open(TableSpaceRelationId, AccessShareLock); ScanKeyInit(&entry[0], Anum_pg_tablespace_spcname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(tablespacename)); scandesc = heap_beginscan(rel, SnapshotNow, 1, entry); tuple = heap_getnext(scandesc, ForwardScanDirection); if (HeapTupleIsValid(tuple)) result = HeapTupleGetOid(tuple); else result = InvalidOid; heap_endscan(scandesc); heap_close(rel, AccessShareLock); return result;}/* * get_tablespace_name - given a tablespace OID, look up the name * * Returns a palloc'd string, or NULL if no such tablespace. */char *get_tablespace_name(Oid spc_oid){ char *result; Relation rel; HeapScanDesc scandesc; HeapTuple tuple; ScanKeyData entry[1]; /* Search pg_tablespace */ rel = heap_open(TableSpaceRelationId, AccessShareLock); ScanKeyInit(&entry[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(spc_oid)); scandesc = heap_beginscan(rel, SnapshotNow, 1, entry); tuple = heap_getnext(scandesc, ForwardScanDirection); /* We assume that there can be at most one matching tuple */ if (HeapTupleIsValid(tuple)) result = pstrdup(NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname)); else result = NULL; heap_endscan(scandesc); heap_close(rel, AccessShareLock); return result;}/* * TABLESPACE resource manager's routines */voidtblspc_redo(XLogRecPtr lsn, XLogRecord *record){ uint8 info = record->xl_info & ~XLR_INFO_MASK; if (info == XLOG_TBLSPC_CREATE) { xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) XLogRecGetData(record); char *location = xlrec->ts_path; char *linkloc; /* * Attempt to coerce target directory to safe permissions. If this * fails, it doesn't exist or has the wrong owner. */ if (chmod(location, 0700) != 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not set permissions on directory \"%s\": %m", location))); /* Create or re-create the PG_VERSION file in the target directory */ set_short_version(location); /* Create the symlink if not already present */ linkloc = (char *) palloc(10 + 10 + 1); sprintf(linkloc, "pg_tblspc/%u", xlrec->ts_id); if (symlink(location, linkloc) < 0) { if (errno != EEXIST) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create symbolic link \"%s\": %m", linkloc))); } pfree(linkloc); } else if (info == XLOG_TBLSPC_DROP) { xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) XLogRecGetData(record); if (!remove_tablespace_directories(xlrec->ts_id, true)) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("tablespace %u is not empty", xlrec->ts_id))); } else elog(PANIC, "tblspc_redo: unknown op code %u", info);}voidtblspc_desc(char *buf, uint8 xl_info, char *rec){ uint8 info = xl_info & ~XLR_INFO_MASK; if (info == XLOG_TBLSPC_CREATE) { xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec; sprintf(buf + strlen(buf), "create ts: %u \"%s\"", xlrec->ts_id, xlrec->ts_path); } else if (info == XLOG_TBLSPC_DROP) { xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec; sprintf(buf + strlen(buf), "drop ts: %u", xlrec->ts_id); } else strcat(buf, "UNKNOWN");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -