1111 *
1212 * NOTES:
1313 *
14- * This fileimplemets compression of file pages.
14+ * This fileimplements compression of file pages.
1515 * Updated compressed pages are always appended to the end of file segment.
16- * Garbage collector is used to shrink files when them become tool large.
17- * GC is spawned as one or more background workers. Them recursively traverse all tablespace directories,
18- * find out *.cfm files are if logical size of the file is twice larger than physical size of the file
19- * performs compactification. Locking implemented using atomic operations is used to eliminate race
20- * conditions.
16+ * Garbage collector is used to reclaim storage occupied by outdated versions of pages.
17+ * GC runs one or more background workers which recursively traverse all tablespace
18+ * directories. If worker finds out that logical size of the file is twice as large as
19+ * physical size of the file, it performs compactification.
20+ * To eliminate race conditions, files are locked during compacification.
21+ * Locks are implemented with atomic operations.
22+ *
23+ * TODO Write a note about *.cfm files.
2124 */
2225
2326#include "postgres.h"
5154#include "utils/resowner_private.h"
5255#include "postmaster/bgworker.h"
5356
57+ /*
58+ * GUC variable that defines compression level.
59+ * 0 - no compression, 1 - max speed,
60+ * other possible values depend on the specific algorithm.
61+ * Default value is 1.
62+ */
63+ int cfs_level ;
64+ /*
65+ * GUC variable that defines if encryption of compressed pages is enabled.
66+ * Default value is false.
67+ */
68+ bool cfs_encryption ;
69+ /*
70+ * GUC variable - Verify correctness of data written by GC.
71+ * TODO add description and documentation.
72+ */
73+ bool cfs_gc_verify_file ;
74+
75+ /* GUC variable - Number of garbage collection background workers. Default = 1 */
5476int cfs_gc_workers ;
77+ /*
78+ * GUC variable - Specifies the minimum percent of garbage blocks
79+ * needed to trigger a GC of the file. Default = 50
80+ */
5581int cfs_gc_threshold ;
82+ /* GUC variable - Time to sleep between GC runs in milliseconds. Default = 5000 */
5683int cfs_gc_period ;
84+ /* GUC variable - Delay in milliseconds between files defragmentation. Default = 0
85+ * TODO What is the purpose of this variable?
86+ */
5787int cfs_gc_delay ;
58- int cfs_level ;
59- bool cfs_encryption ;
60- bool cfs_gc_verify_file ;
6188
6289static bool cfs_read_file (int fd ,void * data ,uint32 size );
6390static bool cfs_write_file (int fd ,void const * data ,uint32 size );
@@ -68,90 +95,109 @@ CfsState* cfs_state;
6895static bool cfs_stop ;
6996static int cfs_processed_segments ;
7097
71- #if CFS_COMPRESSOR == SNAPPY_COMPRESSOR
7298
73- #include <snappy-c.h>
99+ /* ----------------------------------------------------------------
100+ *Section 1: Various compression algorithms.
101+ * CFS_COMPRESSOR variable can be set at compile time.
102+ * One should define CFS_COMPRESSOR in cfs.h
103+ * Availiable options are:
104+ * - LZ_COMPRESSOR // FIXME. No actual implementation.
105+ * - ZLIB_COMPRESSOR
106+ * - LZ4_COMPRESSOR
107+ * - SNAPPY_COMPRESSOR
108+ * - LCFSE_COMPRESSOR
109+ * - ZSTD_COMPRESSOR
110+ *
111+ * If none of options is chosen, use standard pglz_compress FIXME?, which is
112+ * slow and non-efficient in comparison with others, but doesn't requre
113+ * any extra libraries.
114+ * ----------------------------------------------------------------
115+ */
116+
117+ #if CFS_COMPRESSOR == ZLIB_COMPRESSOR
118+
119+ #include <zlib.h>
74120
75121size_t cfs_compress (void * dst ,size_t dst_size ,void const * src ,size_t src_size )
76122{
77- return snappy_compress (src ,src_size ,dst ,& dst_size )== SNAPPY_OK ?dst_size :0 ;
123+ uLongf compressed_size = dst_size ;
124+ int rc = compress2 (dst ,& compressed_size ,src ,src_size ,cfs_level );
125+ return rc == Z_OK ?compressed_size :rc ;
78126}
79127
80128size_t cfs_decompress (void * dst ,size_t dst_size ,void const * src ,size_t src_size )
81129{
82- return snappy_uncompress (src ,src_size ,dst ,& dst_size )== SNAPPY_OK ?dst_size :0 ;
130+ uLongf dest_len = dst_size ;
131+ int rc = uncompress (dst ,& dest_len ,src ,src_size );
132+ return rc == Z_OK ?dest_len :rc ;
83133}
84134
85135char const * cfs_algorithm ()
86136{
87- return "snappy " ;
137+ return "zlib " ;
88138}
89139
90- #elif CFS_COMPRESSOR == LCFSE_COMPRESSOR
140+ #elif CFS_COMPRESSOR == LZ4_COMPRESSOR
91141
92- #include <lcfse .h>
142+ #include <lz4 .h>
93143
94144size_t cfs_compress (void * dst ,size_t dst_size ,void const * src ,size_t src_size )
95145{
96- char * scratch_buf = palloc (lcfse_encode_scratch_size ());
97- size_t rc = lcfse_encode_buffer (dst ,dst_size ,src ,src_size ,scratch_buf );
98- pfree (scratch_buf );
99- return rc ;
146+ return LZ4_compress (src ,dst ,src_size );
100147}
101148
102149size_t cfs_decompress (void * dst ,size_t dst_size ,void const * src ,size_t src_size )
103150{
104- char * scratch_buf = palloc (lcfse_encode_scratch_size ());
105- size_t rc = lcfse_decode_buffer (dst ,dst_size ,src ,src_size ,scratch_buf );
106- pfree (scratch_buf );
107- return rc ;
151+ return LZ4_decompress_safe (src ,dst ,src_size ,dst_size );
108152}
109153
110154char const * cfs_algorithm ()
111155{
112- return "lcfse " ;
156+ return "lz4 " ;
113157}
114158
115- #elif CFS_COMPRESSOR == LZ4_COMPRESSOR
159+ #elif CFS_COMPRESSOR == SNAPPY_COMPRESSOR
116160
117- #include <lz4 .h>
161+ #include <snappy-c .h>
118162
119163size_t cfs_compress (void * dst ,size_t dst_size ,void const * src ,size_t src_size )
120164{
121- return LZ4_compress (src ,dst ,src_size ) ;
165+ return snappy_compress (src ,src_size , dst ,& dst_size ) == SNAPPY_OK ? dst_size : 0 ;
122166}
123167
124168size_t cfs_decompress (void * dst ,size_t dst_size ,void const * src ,size_t src_size )
125169{
126- return LZ4_decompress_safe (src ,dst , src_size , dst_size );
170+ return snappy_uncompress (src ,src_size , dst , & dst_size )== SNAPPY_OK ? dst_size : 0 ;
127171}
128172
129173char const * cfs_algorithm ()
130174{
131- return "lz4 " ;
175+ return "snappy " ;
132176}
133177
134- #elif CFS_COMPRESSOR == ZLIB_COMPRESSOR
178+ #elif CFS_COMPRESSOR == LCFSE_COMPRESSOR
135179
136- #include <zlib .h>
180+ #include <lcfse .h>
137181
138182size_t cfs_compress (void * dst ,size_t dst_size ,void const * src ,size_t src_size )
139183{
140- uLongf compressed_size = dst_size ;
141- int rc = compress2 (dst ,& compressed_size ,src ,src_size ,cfs_level );
142- return rc == Z_OK ?compressed_size :rc ;
184+ char * scratch_buf = palloc (lcfse_encode_scratch_size ());
185+ size_t rc = lcfse_encode_buffer (dst ,dst_size ,src ,src_size ,scratch_buf );
186+ pfree (scratch_buf );
187+ return rc ;
143188}
144189
145190size_t cfs_decompress (void * dst ,size_t dst_size ,void const * src ,size_t src_size )
146191{
147- uLongf dest_len = dst_size ;
148- int rc = uncompress (dst ,& dest_len ,src ,src_size );
149- return rc == Z_OK ?dest_len :rc ;
192+ char * scratch_buf = palloc (lcfse_encode_scratch_size ());
193+ size_t rc = lcfse_decode_buffer (dst ,dst_size ,src ,src_size ,scratch_buf );
194+ pfree (scratch_buf );
195+ return rc ;
150196}
151197
152198char const * cfs_algorithm ()
153199{
154- return "zlib " ;
200+ return "lcfse " ;
155201}
156202
157203#elif CFS_COMPRESSOR == ZSTD_COMPRESSOR
@@ -195,6 +241,15 @@ char const* cfs_algorithm()
195241#endif
196242
197243
244+ /* ----------------------------------------------------------------
245+ *Section 2: Encryption related functionality.
246+ *
247+ * TODO
248+ * - replace rc4 algrithm with something more appropriate
249+ * - add more comments
250+ * - what does 'offs' variable for?
251+ * ----------------------------------------------------------------
252+ */
198253static void cfs_rc4_encrypt_block (void * block ,uint32 offs ,uint32 block_size )
199254{
200255uint32 i ;
@@ -205,7 +260,7 @@ static void cfs_rc4_encrypt_block(void* block, uint32 offs, uint32 block_size)
205260int x = 0 ,y = 0 ;
206261uint32 skip = (offs /BLCKSZ + block_size ) %CFS_CIPHER_KEY_SIZE ;
207262
208- memcpy (state ,cfs_state -> rc4_init_state ,CFS_CIPHER_KEY_SIZE );
263+ memcpy (state ,cfs_state -> cipher_key ,CFS_CIPHER_KEY_SIZE );
209264for (i = 0 ;i < skip ;i ++ ) {
210265x = (x + 1 ) %CFS_CIPHER_KEY_SIZE ;
211266y = (y + state [x ]) %CFS_CIPHER_KEY_SIZE ;
@@ -224,7 +279,12 @@ static void cfs_rc4_encrypt_block(void* block, uint32 offs, uint32 block_size)
224279 }
225280}
226281
227- static void cfs_rc4_init (void )
282+ /*
283+ * Get env variable PG_CIPHER_KEY and initialize encryption state.
284+ * Unset variable afterward.
285+ * Now implements cf4.
286+ */
287+ static void cfs_encrypt_init (void )
228288{
229289int index1 = 0 ;
230290int index2 = 0 ;
@@ -233,13 +293,13 @@ static void cfs_rc4_init(void)
233293int key_length ;
234294int x = 0 ,y = 0 ;
235295char * cipher_key ;
236- uint8 * rc4_init_state = cfs_state -> rc4_init_state ;
296+ uint8 * rc4_init_state = cfs_state -> cipher_key ;
237297
238298cipher_key = getenv ("PG_CIPHER_KEY" );
239299if (cipher_key == NULL ) {
240300elog (ERROR ,"PG_CIPHER_KEY environment variable is not set" );
241301}
242- unsetenv ("PG_CIPHER_KEY" );/*make it not possible to inspect this environment variable through plperl */
302+ unsetenv ("PG_CIPHER_KEY" );/*disable inspection of this environment variable */
243303key_length = strlen (cipher_key );
244304for (i = 0 ;i < CFS_CIPHER_KEY_SIZE ;++ i ) {
245305rc4_init_state [i ]= (uint8 )i ;
@@ -263,20 +323,21 @@ static void cfs_rc4_init(void)
263323void cfs_encrypt (void * block ,uint32 offs ,uint32 size )
264324{
265325if (cfs_encryption )
266- {
267326cfs_rc4_encrypt_block (block ,offs ,size );
268- }
269327}
270328
271329void cfs_decrypt (void * block ,uint32 offs ,uint32 size )
272330{
273331if (cfs_encryption )
274- {
275332cfs_rc4_encrypt_block (block ,offs ,size );
276- }
277333}
278334
279-
335+ /* ----------------------------------------------------------------
336+ *Section 3: Compression implementation.
337+ *
338+ * TODO add description
339+ * ----------------------------------------------------------------
340+ */
280341void cfs_initialize ()
281342{
282343cfs_state = (CfsState * )ShmemAlloc (sizeof (CfsState ));
@@ -287,9 +348,9 @@ void cfs_initialize()
287348cfs_state -> gc_enabled = true;
288349cfs_state -> max_iterations = 0 ;
289350
290- if (cfs_encryption ) {
291- cfs_rc4_init ();
292- }
351+ if (cfs_encryption )
352+ cfs_encrypt_init ();
353+
293354elog (LOG ,"Start CFS version %s compression algorithm %s encryption %s" ,
294355CFS_VERSION ,cfs_algorithm (),cfs_encryption ?"enabled" :"disabled" );
295356}
@@ -463,6 +524,12 @@ static int cfs_cmp_page_offs(void const* p1, void const* p2)
463524return o1 < o2 ?-1 :o1 == o2 ?0 :1 ;
464525}
465526
527+ /* ----------------------------------------------------------------
528+ *Section 4: Garbage collection functionality.
529+ *
530+ * TODO add description. reorder functions.
531+ * ----------------------------------------------------------------
532+ */
466533/*
467534 * Perform garbage collection (if required) of file
468535 * @param map_path path to file map file (*.cfm).