4848
4949#include <unistd.h>
5050#include <dirent.h>
51+ #include <stdio.h>
5152#include <sys/types.h>
5253#include <sys/stat.h>
5354
6566#include "catalog/objectaccess.h"
6667#include "catalog/pg_namespace.h"
6768#include "catalog/pg_tablespace.h"
69+ #include "commands/defrem.h"
6870#include "commands/comment.h"
6971#include "commands/seclabel.h"
7072#include "commands/tablecmds.h"
7173#include "commands/tablespace.h"
7274#include "miscadmin.h"
7375#include "postmaster/bgwriter.h"
7476#include "storage/fd.h"
77+ #include "storage/cfs.h"
7578#include "storage/lmgr.h"
7679#include "storage/standby.h"
7780#include "utils/acl.h"
7881#include "utils/builtins.h"
7982#include "utils/fmgroids.h"
8083#include "utils/guc.h"
8184#include "utils/lsyscache.h"
85+ #include "utils/spccache.h"
8286#include "utils/memutils.h"
8387#include "utils/rel.h"
8488#include "utils/tqual.h"
@@ -90,7 +94,7 @@ char *temp_tablespaces = NULL;
9094
9195
9296static void create_tablespace_directories (const char * location ,
93- const Oid tablespaceoid );
97+ const Oid tablespaceoid , bool compressed );
9498static bool destroy_tablespace_directories (Oid tablespaceoid ,bool redo );
9599
96100
@@ -222,6 +226,23 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo)
222226pfree (dir );
223227}
224228
229+ static bool
230+ getBoolOption (List * options ,char const * name ,bool defaultValue )
231+ {
232+ ListCell * cell ;
233+ foreach (cell ,options )
234+ {
235+ DefElem * def = (DefElem * )lfirst (cell );
236+ if (strcmp (def -> defname ,name )== 0 )
237+ {
238+ return defGetBoolean (def );
239+ }
240+ }
241+ return defaultValue ;
242+ }
243+
244+
245+
225246/*
226247 * Create a table space
227248 *
@@ -241,6 +262,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
241262char * location ;
242263Oid ownerId ;
243264Datum newOptions ;
265+ bool compressed ;
244266
245267/* Must be super user */
246268if (!superuser ())
@@ -256,6 +278,9 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
256278else
257279ownerId = GetUserId ();
258280
281+ /* If tablespace should be compressed */
282+ compressed = getBoolOption (stmt -> options ,"compression" , false);
283+
259284/* Unix-ify the offered path, and strip any trailing slashes */
260285location = pstrdup (stmt -> location );
261286canonicalize_path (location );
@@ -355,14 +380,14 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
355380/* Post creation hook for new tablespace */
356381InvokeObjectPostCreateHook (TableSpaceRelationId ,tablespaceoid ,0 );
357382
358- create_tablespace_directories (location ,tablespaceoid );
383+ create_tablespace_directories (location ,tablespaceoid , getBoolOption ( stmt -> options , "compression" , false) );
359384
360385/* Record the filesystem change in XLOG */
361386{
362387xl_tblspc_create_rec xlrec ;
363388
364389xlrec .ts_id = tablespaceoid ;
365-
390+ xlrec . ts_compressed = compressed ;
366391XLogBeginInsert ();
367392XLogRegisterData ((char * )& xlrec ,
368393 offsetof(xl_tblspc_create_rec ,ts_path ));
@@ -562,7 +587,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
562587 *to the specified directory
563588 */
564589static void
565- create_tablespace_directories (const char * location ,const Oid tablespaceoid )
590+ create_tablespace_directories (const char * location ,const Oid tablespaceoid , bool compressed )
566591{
567592char * linkloc ;
568593char * location_with_version_dir ;
@@ -626,6 +651,16 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid)
626651location_with_version_dir )));
627652}
628653
654+ if (compressed )
655+ {
656+ char * compressionFilePath = psprintf ("%s/pg_compression" ,location_with_version_dir );
657+ FILE * comp = fopen (compressionFilePath ,"w" );
658+ elog (LOG ,"Create compressed tablespace at %s" ,location );
659+ fputs (cfs_algorithm (),comp );
660+ fclose (comp );
661+ pfree (compressionFilePath );
662+ }
663+
629664/*
630665 * In recovery, remove old symlink, in case it points to the wrong place.
631666 */
@@ -664,6 +699,7 @@ destroy_tablespace_directories(Oid tablespaceoid, bool redo)
664699{
665700char * linkloc ;
666701char * linkloc_with_version_dir ;
702+ char * compression_file ;
667703DIR * dirdesc ;
668704struct dirent * de ;
669705char * subfile ;
@@ -672,6 +708,9 @@ destroy_tablespace_directories(Oid tablespaceoid, bool redo)
672708linkloc_with_version_dir = psprintf ("pg_tblspc/%u/%s" ,tablespaceoid ,
673709TABLESPACE_VERSION_DIRECTORY );
674710
711+ compression_file = psprintf ("%s/pg_compression" ,linkloc_with_version_dir );
712+ unlink (compression_file );
713+
675714/*
676715 * Check if the tablespace still contains any files. We try to rmdir each
677716 * per-database directory we find in it. rmdir failure implies there are
@@ -840,7 +879,8 @@ directory_is_empty(const char *path)
840879while ((de = ReadDir (dirdesc ,path ))!= NULL )
841880{
842881if (strcmp (de -> d_name ,"." )== 0 ||
843- strcmp (de -> d_name ,".." )== 0 )
882+ strcmp (de -> d_name ,".." )== 0 ||
883+ strcmp (de -> d_name ,"pg_compression" )== 0 )
844884continue ;
845885FreeDir (dirdesc );
846886return false;
@@ -1000,6 +1040,7 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
10001040bool repl_null [Natts_pg_tablespace ];
10011041bool repl_repl [Natts_pg_tablespace ];
10021042HeapTuple newtuple ;
1043+ bool compressed ;
10031044
10041045/* Search pg_tablespace */
10051046rel = heap_open (TableSpaceRelationId ,RowExclusiveLock );
@@ -1018,6 +1059,27 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
10181059
10191060tablespaceoid = HeapTupleGetOid (tup );
10201061
1062+ /* If tablespace should be compressed */
1063+ compressed = getBoolOption (stmt -> options ,"compression" , false);
1064+
1065+ if (compressed ^is_tablespace_compressed (tablespaceoid )) {
1066+ char * tbsdir = psprintf ("pg_tblspc/%u/%s" ,tablespaceoid ,TABLESPACE_VERSION_DIRECTORY );
1067+ if (!directory_is_empty (tbsdir )) {
1068+ ereport (ERROR ,
1069+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
1070+ errmsg ("It is not possible to toggle compression option for tablespace" )));
1071+ }else {
1072+ char * compressionFilePath = psprintf ("%s/pg_compression" ,tbsdir );
1073+ if (compressed ) {
1074+ FILE * comp = fopen (compressionFilePath ,"w" );
1075+ fputs (cfs_algorithm (),comp );
1076+ fclose (comp );
1077+ }else {
1078+ unlink (compressionFilePath );
1079+ }
1080+ }
1081+ }
1082+
10211083/* Must be owner of the existing object */
10221084if (!pg_tablespace_ownercheck (HeapTupleGetOid (tup ),GetUserId ()))
10231085aclcheck_error (ACLCHECK_NOT_OWNER ,ACL_KIND_TABLESPACE ,
@@ -1478,7 +1540,7 @@ tblspc_redo(XLogReaderState *record)
14781540xl_tblspc_create_rec * xlrec = (xl_tblspc_create_rec * )XLogRecGetData (record );
14791541char * location = xlrec -> ts_path ;
14801542
1481- create_tablespace_directories (location ,xlrec -> ts_id );
1543+ create_tablespace_directories (location ,xlrec -> ts_id , xlrec -> ts_compressed );
14821544}
14831545else if (info == XLOG_TBLSPC_DROP )
14841546{