@@ -257,9 +257,9 @@ static void cfs_crypto_init(void)
257257uint8 aes_key [32 ]= {0 };/* at most 256 bits */
258258
259259cipher_key = getenv ("PG_CIPHER_KEY" );
260- if (cipher_key == NULL ) {
260+ if (cipher_key == NULL ) {
261261elog (ERROR ,"PG_CIPHER_KEY environment variable is not set" );
262- }
262+ }
263263unsetenv ("PG_CIPHER_KEY" );/* disable inspection of this environment variable */
264264key_length = strlen (cipher_key );
265265
@@ -406,11 +406,11 @@ void cfs_initialize()
406406cfs_state -> n_workers = 0 ;
407407cfs_state -> gc_enabled = cfs_gc_enabled ;
408408cfs_state -> max_iterations = 0 ;
409-
409+
410410if (cfs_encryption )
411411cfs_crypto_init ();
412-
413- elog (LOG ,"Start CFS version %s compression algorithm %s encryption %s GC %s" ,
412+
413+ elog (LOG ,"Start CFS version %s compression algorithm %s encryption %s GC %s" ,
414414CFS_VERSION ,cfs_algorithm (),cfs_encryption ?"enabled" :"disabled" ,cfs_gc_enabled ?"enabled" :"disabled" );
415415}
416416}
@@ -426,19 +426,19 @@ int cfs_msync(FileMap* map)
426426FileMap * cfs_mmap (int md )
427427{
428428FileMap * map ;
429- if (ftruncate (md ,sizeof (FileMap ))!= 0 )
429+ if (ftruncate (md ,sizeof (FileMap ))!= 0 )
430430{
431431return (FileMap * )MAP_FAILED ;
432432}
433-
433+
434434#ifdef WIN32
435435{
436- HANDLE mh = CreateFileMapping (_get_osfhandle (md ),NULL ,PAGE_READWRITE ,
436+ HANDLE mh = CreateFileMapping (_get_osfhandle (md ),NULL ,PAGE_READWRITE ,
4374370 , (DWORD )sizeof (FileMap ),NULL );
438438if (mh == NULL )
439439return (FileMap * )MAP_FAILED ;
440440
441- map = (FileMap * )MapViewOfFile (mh ,FILE_MAP_ALL_ACCESS ,0 ,0 ,0 );
441+ map = (FileMap * )MapViewOfFile (mh ,FILE_MAP_ALL_ACCESS ,0 ,0 ,0 );
442442CloseHandle (mh );
443443}
444444if (map == NULL )
@@ -499,7 +499,7 @@ static bool cfs_read_file(int fd, void* data, uint32 size)
499499else
500500offs += rc ;
501501}while (offs < size );
502-
502+
503503return true;
504504}
505505
@@ -519,7 +519,7 @@ static bool cfs_write_file(int fd, void const* data, uint32 size)
519519else
520520offs += rc ;
521521}while (offs < size );
522-
522+
523523return true;
524524}
525525
@@ -559,23 +559,23 @@ void cfs_lock_file(FileMap* map, char const* file_path)
559559break ;
560560}
561561
562- if (pg_atomic_read_u32 (& cfs_state -> n_active_gc )== 0 )
563- {
562+ if (pg_atomic_read_u32 (& cfs_state -> n_active_gc )== 0 )
563+ {
564564/* There is no active GC, so lock is set by crashed GC */
565565
566566LWLockAcquire (CfsGcLock ,LW_EXCLUSIVE );/* Prevent race condition with GC */
567567
568568/* Recheck under CfsGcLock that map->lock was not released */
569- if (pg_atomic_read_u32 (& map -> lock ) >=CFS_GC_LOCK )
569+ if (pg_atomic_read_u32 (& map -> lock ) >=CFS_GC_LOCK )
570570{
571571/* Uhhh... looks like last GC was interrupted.
572572 * Try to recover the file.
573573 */
574574char * map_bck_path = psprintf ("%s.cfm.bck" ,file_path );
575575char * file_bck_path = psprintf ("%s.bck" ,file_path );
576-
576+
577577elog (WARNING ,"CFS indicates that GC of %s was interrupted: trying to perform recovery" ,file_path );
578-
578+
579579if (access (file_bck_path ,R_OK )!= 0 )
580580{
581581/* There is no backup file: new map should be constructed */
@@ -585,20 +585,20 @@ void cfs_lock_file(FileMap* map, char const* file_path)
585585/* Recover map. */
586586if (!cfs_read_file (md2 ,map ,sizeof (FileMap )))
587587elog (WARNING ,"CFS failed to read file %s: %m" ,map_bck_path );
588-
588+
589589close (md2 );
590590}
591591}
592592else
593593{
594594/* Presence of backup file means that we still have
595- * unchanged data and map files. Just remove backup files and
595+ * unchanged data and map files. Just remove backup files and
596596 * revoke GC lock.
597597 */
598598unlink (file_bck_path );
599599unlink (map_bck_path );
600600}
601-
601+
602602count = pg_atomic_fetch_sub_u32 (& map -> lock ,CFS_GC_LOCK );/* revoke GC lock */
603603Assert ((int )count > 0 );
604604pfree (file_bck_path );
@@ -634,12 +634,13 @@ void cfs_unlock_file(FileMap* map)
634634/*
635635 * Sort pages by offset to improve access locality
636636 */
637- static int cfs_cmp_page_offs (void const * p1 ,void const * p2 )
637+ static int cfs_cmp_page_offs (void const * p1 ,void const * p2 )
638638{
639639uint32 o1 = CFS_INODE_OFFS (* * (inode_t * * )p1 );
640640uint32 o2 = CFS_INODE_OFFS (* * (inode_t * * )p2 );
641641return o1 < o2 ?-1 :o1 == o2 ?0 :1 ;
642642}
643+
643644/*
644645 * Perform garbage collection (if required) on the file
645646 * @param map_path - path to the map file (*.cfm).
@@ -658,7 +659,7 @@ static bool cfs_gc_file(char* map_path, bool background)
658659int md2 = -1 ;
659660bool succeed = false;
660661int rc ;
661-
662+
662663
663664pg_atomic_fetch_add_u32 (& cfs_state -> n_active_gc ,1 );
664665
@@ -667,13 +668,13 @@ static bool cfs_gc_file(char* map_path, bool background)
667668while (!cfs_state -> gc_enabled )
668669{
669670pg_atomic_fetch_sub_u32 (& cfs_state -> n_active_gc ,1 );
670-
671+
671672rc = WaitLatch (MyLatch ,
672673WL_TIMEOUT |WL_POSTMASTER_DEATH ,
673674CFS_DISABLE_TIMEOUT /* ms */ );
674675if (cfs_gc_stop || (rc & WL_POSTMASTER_DEATH ))
675676exit (1 );
676-
677+
677678pg_atomic_fetch_add_u32 (& cfs_state -> n_active_gc ,1 );
678679}
679680
@@ -682,7 +683,7 @@ static bool cfs_gc_file(char* map_path, bool background)
682683
683684md = open (map_path ,O_RDWR |PG_BINARY ,0 );
684685if (md < 0 )
685- {
686+ {
686687elog (DEBUG1 ,"CFS failed to open map file %s: %m" ,map_path );
687688gotoFinishGC ;
688689}
@@ -699,7 +700,7 @@ static bool cfs_gc_file(char* map_path, bool background)
699700usedSize = pg_atomic_read_u32 (& map -> usedSize );
700701physSize = pg_atomic_read_u32 (& map -> physSize );
701702virtSize = pg_atomic_read_u32 (& map -> virtSize );
702-
703+
703704cfs_state -> gc_stat .scannedFiles += 1 ;
704705
705706/* do we need to perform defragmentation? */
@@ -804,7 +805,7 @@ static bool cfs_gc_file(char* map_path, bool background)
804805}
805806/* sort inodes by offset to improve read locality */
806807qsort (inodes ,n_pages ,sizeof (inode_t * ),cfs_cmp_page_offs );
807-
808+
808809fd = open (file_path ,O_RDONLY |PG_BINARY ,0 );
809810if (fd < 0 )
810811gotoCleanup ;
@@ -927,9 +928,8 @@ static bool cfs_gc_file(char* map_path, bool background)
927928if (res != BLCKSZ )
928929{
929930pg_atomic_fetch_sub_u32 (& map -> lock ,CFS_GC_LOCK );/* release lock */
930- /* TODO Is it worth to PANIC or ERROR will be enough? */
931- elog (PANIC ,"Verification failed for block %d of relation %s: error code %d" ,
932- i ,file_bck_path , (int )res );
931+ elog (ERROR ,"Verification failed for block %d position %d size %d of relation %s: error code %d" ,
932+ i , (int )CFS_INODE_OFFS (inode ),size ,file_bck_path , (int )res );
933933}
934934}
935935}
@@ -977,7 +977,7 @@ static bool cfs_gc_file(char* map_path, bool background)
977977if (remove_backups )
978978{
979979unlink (file_bck_path );
980- unlink (map_bck_path );
980+ unlink (map_bck_path );
981981remove_backups = false;
982982}
983983succeed = false;
@@ -1070,7 +1070,7 @@ static bool cfs_gc_directory(int worker_id, char const* path)
10701070/* If we have found a map file, run gc worker on it.
10711071 * Otherwise, try to gc the directory recursively.
10721072 */
1073- if (len > 4 &&
1073+ if (len > 4 &&
10741074strcmp (file_path + len - 4 ,".cfm" )== 0 )
10751075{
10761076if (entry -> d_ino %cfs_state -> n_workers == worker_id
@@ -1080,7 +1080,7 @@ static bool cfs_gc_directory(int worker_id, char const* path)
10801080break ;
10811081}
10821082}
1083- else if (!cfs_gc_directory (worker_id ,file_path ))
1083+ else if (!cfs_gc_directory (worker_id ,file_path ))
10841084{
10851085success = false;
10861086break ;
@@ -1124,7 +1124,7 @@ static void cfs_gc_bgworker_main(Datum arg)
11241124int timeout = cfs_gc_period ;
11251125int rc ;
11261126
1127- if (!cfs_gc_scan_tablespace (worker_id ))
1127+ if (!cfs_gc_scan_tablespace (worker_id ))
11281128{
11291129timeout = CFS_RETRY_TIMEOUT ;
11301130}
@@ -1148,7 +1148,7 @@ void cfs_gc_start_bgworkers()
11481148
11491149for (i = 0 ;i < cfs_gc_workers ;i ++ )
11501150{
1151- BackgroundWorker worker ;
1151+ BackgroundWorker worker ;
11521152BackgroundWorkerHandle * handle ;
11531153MemSet (& worker ,0 ,sizeof (worker ));
11541154sprintf (worker .bgw_name ,"cfs-worker-%d" ,i );
@@ -1165,9 +1165,9 @@ void cfs_gc_start_bgworkers()
11651165}
11661166
11671167/* Enable/disable garbage colection. */
1168- bool cfs_control_gc (bool enabled )
1168+ bool cfs_control_gc (bool enabled )
11691169{
1170- bool was_enabled = cfs_state -> gc_enabled ;
1170+ bool was_enabled = cfs_state -> gc_enabled ;
11711171cfs_state -> gc_enabled = enabled ;
11721172if (was_enabled && !enabled )
11731173{
@@ -1272,7 +1272,7 @@ Datum cfs_estimate(PG_FUNCTION_ARGS)
12721272off_t step = rc /BLCKSZ /CFS_ESTIMATE_PROBES * BLCKSZ ;
12731273for (i = 0 ;i < CFS_ESTIMATE_PROBES ;i ++ )
12741274{
1275- rc = lseek (fd ,step * i ,SEEK_SET );
1275+ rc = lseek (fd ,step * i ,SEEK_SET );
12761276if (rc < 0 )
12771277break ;
12781278
@@ -1406,7 +1406,7 @@ Datum cfs_gc_relation(PG_FUNCTION_ARGS)
14061406Oid oid = PG_GETARG_OID (0 );
14071407Relation rel = try_relation_open (oid ,AccessShareLock );
14081408int processed_segments = 0 ;
1409-
1409+
14101410if (rel != NULL )
14111411{
14121412char * path ;
@@ -1420,7 +1420,7 @@ Datum cfs_gc_relation(PG_FUNCTION_ARGS)
14201420path = relpathbackend (rel -> rd_node ,rel -> rd_backend ,MAIN_FORKNUM );
14211421map_path = (char * )palloc (strlen (path )+ 16 );
14221422sprintf (map_path ,"%s.cfm" ,path );
1423-
1423+
14241424while (cfs_gc_file (map_path , false))
14251425{
14261426sprintf (map_path ,"%s.%u.cfm" ,path ,++ i );
@@ -1436,6 +1436,21 @@ Datum cfs_gc_relation(PG_FUNCTION_ARGS)
14361436PG_RETURN_INT32 (cfs_gc_processed_segments );
14371437}
14381438
1439+
1440+ void cfs_gc_segment (char const * fileName )
1441+ {
1442+ char * mapFileName = psprintf ("%s.cfm" ,fileName );
1443+
1444+ LWLockAcquire (CfsGcLock ,LW_EXCLUSIVE );/* Prevent interaction with background GC */
1445+
1446+ cfs_gc_file (mapFileName , false);
1447+
1448+ LWLockRelease (CfsGcLock );
1449+
1450+ pfree (mapFileName );
1451+ }
1452+
1453+
14391454Datum cfs_gc_activity_processed_bytes (PG_FUNCTION_ARGS )
14401455{
14411456PG_RETURN_INT64 (cfs_state -> gc_stat .processedBytes );