@@ -132,7 +132,14 @@ int max_safe_fds = 32; /* default if not changed */
132
132
133
133
#define FileIsNotOpen (file ) (VfdCache[file].fd == VFD_CLOSED)
134
134
135
+ /*
136
+ * Note: a VFD's seekPos is normally always valid, but if for some reason
137
+ * an lseek() fails, it might become set to FileUnknownPos. We can struggle
138
+ * along without knowing the seek position in many cases, but in some places
139
+ * we have to fail if we don't have it.
140
+ */
135
141
#define FileUnknownPos ((off_t) -1)
142
+ #define FilePosIsUnknown (pos ) ((pos) < 0)
136
143
137
144
/* these are the assigned bits in fdstate below: */
138
145
#define FD_TEMPORARY (1 << 0) /* T = delete when closed */
@@ -146,7 +153,7 @@ typedef struct vfd
146
153
File nextFree ; /* link to next free VFD, if in freelist */
147
154
File lruMoreRecently ; /* doubly linked recency-of-use list */
148
155
File lruLessRecently ;
149
- off_t seekPos ; /* current logical file position */
156
+ off_t seekPos ; /* current logical file position, or -1 */
150
157
off_t fileSize ; /* current size of file (0 if not temporary) */
151
158
char * fileName ; /* name of file, or NULL for unused VFD */
152
159
/* NB: fileName is malloc'd, and must be free'd when closing the VFD */
@@ -799,19 +806,33 @@ LruDelete(File file)
799
806
800
807
vfdP = & VfdCache [file ];
801
808
802
- /* delete the vfd record from the LRU ring */
803
- Delete (file );
804
-
805
- /* save the seek position */
806
- vfdP -> seekPos = lseek (vfdP -> fd , (off_t ) 0 , SEEK_CUR );
807
- Assert (vfdP -> seekPos != (off_t ) - 1 );
809
+ /*
810
+ * Normally we should know the seek position, but if for some reason we
811
+ * have lost track of it, try again to get it. If we still can't get it,
812
+ * we have a problem: we will be unable to restore the file seek position
813
+ * when and if the file is re-opened. But we can't really throw an error
814
+ * and refuse to close the file, or activities such as transaction cleanup
815
+ * will be broken.
816
+ */
817
+ if (FilePosIsUnknown (vfdP -> seekPos ))
818
+ {
819
+ vfdP -> seekPos = lseek (vfdP -> fd , (off_t ) 0 , SEEK_CUR );
820
+ if (FilePosIsUnknown (vfdP -> seekPos ))
821
+ elog (LOG , "could not seek file \"%s\" before closing: %m" ,
822
+ vfdP -> fileName );
823
+ }
808
824
809
- /* close the file */
825
+ /*
826
+ * Close the file. We aren't expecting this to fail; if it does, better
827
+ * to leak the FD than to mess up our internal state.
828
+ */
810
829
if (close (vfdP -> fd ))
811
- elog (ERROR , "could not close file \"%s\": %m" , vfdP -> fileName );
812
-
813
- -- nfile ;
830
+ elog (LOG , "could not close file \"%s\": %m" , vfdP -> fileName );
814
831
vfdP -> fd = VFD_CLOSED ;
832
+ -- nfile ;
833
+
834
+ /* delete the vfd record from the LRU ring */
835
+ Delete (file );
815
836
}
816
837
817
838
static void
@@ -862,22 +883,39 @@ LruInsert(File file)
862
883
vfdP -> fileMode );
863
884
if (vfdP -> fd < 0 )
864
885
{
865
- DO_DB (elog (LOG , "RE_OPEN FAILED : %d" , errno ));
886
+ DO_DB (elog (LOG , "re-open failed : %m" ));
866
887
return -1 ;
867
888
}
868
889
else
869
890
{
870
- DO_DB (elog (LOG , "RE_OPEN SUCCESS" ));
871
891
<
8000
td data-grid-cell-id="diff-c3c830e34267c8ad838b09a48aaca47789d4af47b2c283dff221227f06341048-871-891-2" data-line-anchor="diff-c3c830e34267c8ad838b09a48aaca47789d4af47b2c283dff221227f06341048R891" data-selected="false" role="gridcell" style="background-color:var(--bgColor-default);padding-right:24px" tabindex="-1" valign="top" class="focusable-grid-cell diff-text-cell right-side-diff-cell left-side"> ++ nfile ;
872
892
}
873
893
874
- /* seek to the right position */
894
+ /*
895
+ * Seek to the right position. We need no special case for seekPos
896
+ * equal to FileUnknownPos, as lseek() will certainly reject that
897
+ * (thus completing the logic noted in LruDelete() that we will fail
898
+ * to re-open a file if we couldn't get its seek position before
899
+ * closing).
900
+ */
875
901
if (vfdP -> seekPos != (off_t ) 0 )
876
902
{
877
- off_t returnValue PG_USED_FOR_ASSERTS_ONLY ;
878
-
879
- returnValue = lseek (vfdP -> fd , vfdP -> seekPos , SEEK_SET );
880
- Assert (returnValue != (off_t ) - 1 );
903
+ if (lseek (vfdP -> fd , vfdP -> seekPos , SEEK_SET ) < 0 )
904
+ {
905
+ /*
906
+ * If we fail to restore the seek position, treat it like an
907
+ * open() failure.
908
+ */
909
+ int save_errno = errno ;
910
+
911
+ elog (LOG , "could not seek file \"%s\" after re-opening: %m" ,
912
+ vfdP -> fileName );
913
+ (void ) close (vfdP -> fd );
914
+ vfdP -> fd = VFD_CLOSED ;
915
+ -- nfile ;
916
+ errno = save_errno ;
917
+ return -1 ;
918
+ }
881
919
}
882
920
}
883
921
@@ -1260,15 +1298,15 @@ FileClose(File file)
1260
1298
1261
1299
if (!FileIsNotOpen (file ))
1262
1300
{
1263
- /* remove the file from the lru ring */
1264
- Delete (file );
1265
-
1266
1301
/* close the file */
1267
1302
if (close (vfdP -> fd ))
1268
- elog (ERROR , "could not close file \"%s\": %m" , vfdP -> fileName );
1303
+ elog (LOG , "could not close file \"%s\": %m" , vfdP -> fileName );
1269
1304
1270
1305
-- nfile ;
1271
1306
vfdP -> fd = VFD_CLOSED ;
1307
+
1308
+ /* remove the file from the lru ring */
1309
+ Delete (file );
1272
1310
}
1273
1311
1274
1312
/*
@@ -1373,6 +1411,7 @@ int
1373
1411
FileRead (File file , char * buffer , int amount )
1374
1412
{
1375
1413
int returnCode ;
1414
+ Vfd * vfdP ;
1376
1415
1377
1416
Assert (FileIsValid (file ));
1378
1417
@@ -1385,11 +1424,17 @@ FileRead(File file, char *buffer, int amount)
1385
1424
if (returnCode < 0 )
1386
1425
return returnCode ;
1387
1426
1427
+ vfdP = & VfdCache [file ];
1428
+
1388
1429
retry :
1389
- returnCode = read (VfdCache [ file ]. fd , buffer , amount );
1430
+ returnCode = read (vfdP -> fd , buffer , amount );
1390
1431
1391
1432
if (returnCode >= 0 )
1392
- VfdCache [file ].seekPos += returnCode ;
1433
+ {
1434
+ /* if seekPos is unknown, leave it that way */
1435
+ if (!FilePosIsUnknown (vfdP -> seekPos ))
1436
+ vfdP -> seekPos += returnCode ;
1437
+ }
1393
1438
else
1394
1439
{
1395
1440
/*
@@ -1418,7 +1463,7 @@ FileRead(File file, char *buffer, int amount)
1418
1463
goto retry ;
1419
1464
1420
1465
/* Trouble, so assume we don't know the file position anymore */
1421
- VfdCache [ file ]. seekPos = FileUnknownPos ;
1466
+ vfdP -> seekPos = FileUnknownPos ;
1422
1467
}
1423
1468
1424
1469
return returnCode ;
@@ -1428,6 +1473,7 @@ int
1428
1473
FileWrite (File file , char * buffer , int amount )
1429
1474
{
1430
1475
int returnCode ;
1476
+ Vfd * vfdP ;
1431
1477
1432
1478
Assert (FileIsValid (file ));
1433
1479
@@ -1440,6 +1486,8 @@ FileWrite(File file, char *buffer, int amount)
1440
1486
if (returnCode < 0 )
1441
1487
return returnCode ;
1442
1488
1489
+ vfdP = & VfdCache [file ];
1490
+
1443
1491
/*
1444
1492
* If enforcing temp_file_limit and it's a temp file, check to see if the
1445
1493
* write would overrun temp_file_limit, and throw error if so. Note: it's
@@ -1448,15 +1496,28 @@ FileWrite(File file, char *buffer, int amount)
1448
1496
* message if we do that. All current callers would just throw error
1449
1497
* immediately anyway, so this is safe at present.
1450
1498
*/
1451
- if (temp_file_limit >= 0 && (VfdCache [ file ]. fdstate & FD_TEMPORARY ))
1499
+ if (temp_file_limit >= 0 && (vfdP -> fdstate & FD_TEMPORARY ))
1452
1500
{
1453
- off_t newPos = VfdCache [ file ]. seekPos + amount ;
1501
+ off_t newPos ;
1454
1502
1455
- if (newPos > VfdCache [file ].fileSize )
1503
+ /*
1504
+ * Normally we should know the seek position, but if for some reason
1505
+ * we have lost track of it, try again to get it. Here, it's fine to
1506
+ * throw an error if we still can't get it.
1507
+ */
1508
+ if (FilePosIsUnknown (vfdP -> seekPos ))
1509
+ {
1510
+ vfdP -> seekPos = lseek (vfdP -> fd , (off_t ) 0 , SEEK_CUR );
1511
+ if (FilePosIsUnknown (vfdP -> seekPos ))
1512
+ elog (ERROR , "could not seek file \"%s\": %m" , vfdP -> fileName );
1513
+ }
1514
+
1515
+ newPos = vfdP -> seekPos + amount ;
1516
+ if (newPos > vfdP -> fileSize )
1456
1517
{
1457
1518
uint64 newTotal = temporary_files_size ;
1458
1519
1459
- newTotal += newPos - VfdCache [ file ]. fileSize ;
1520
+ newTotal += newPos - vfdP -> fileSize ;
1460
1521
if (newTotal > (uint64 ) temp_file_limit * (uint64 ) 1024 )
1461
1522
ereport (ERROR ,
1462
1523
(errcode (ERRCODE_CONFIGURATION_LIMIT_EXCEEDED ),
@@ -1467,25 +1528,33 @@ FileWrite(File file, char *buffer, int amount)
1467
1528
1468
1529
retry :
1469
1530
errno = 0 ;
1470
- returnCode = write (VfdCache [ file ]. fd , buffer , amount );
1531
+ returnCode = write (vfdP -> fd , buffer , amount );
1471
1532
1472
1533
/* if write didn't set errno, assume problem is no disk space */
1473
1534
if (returnCode != amount && errno == 0 )
1474
1535
errno = ENOSPC ;
1475
1536
1476
1537
if (returnCode >= 0 )
1477
1538
{
1478
- VfdCache [file ].seekPos += returnCode ;
1539
+ /* if seekPos is unknown, leave it that way */
1540
+ if (!FilePosIsUnknown (vfdP -> seekPos ))
1541
+ vfdP -> seekPos += returnCode ;
1479
1542
1480
- /* maintain fileSize and temporary_files_size if it's a temp file */
1481
- if (VfdCache [file ].fdstate & FD_TEMPORARY )
1543
+ /*
1544
+ * Maintain fileSize and temporary_files_size if it's a temp file.
1545
+ *
1546
+ * If seekPos is -1 (unknown), this will do nothing; but we could only
1547
+ * get here in that state if we're not enforcing temporary_files_size,
1548
+ * so we don't care.
1549
+ */
1550
+ if (vfdP -> fdstate & FD_TEMPORARY )
1482
1551
{
1483
- off_t newPos = VfdCache [ file ]. seekPos ;
1552
+ off_t newPos = vfdP -> seekPos ;
1484
1553
1485
- if (newPos > VfdCache [ file ]. fileSize )
1554
+ if (newPos > vfdP -> fileSize )
1486
1555
{
1487
- temporary_files_size += newPos - VfdCache [ file ]. fileSize ;
1488
- VfdCache [ file ]. fileSize = newPos ;
1556
+ temporary_files_size += newPos - vfdP -> fileSize ;
1557
+ vfdP -> fileSize = newPos ;
1489
1558
}
1490
1559
}
1491
1560
}
@@ -1513,7 +1582,7 @@ FileWrite(File file, char *buffer, int amount)
1513
1582
goto retry ;
1514
1583
1515
1584
/* Trouble, so assume we don't know the file position anymore */
1516
- VfdCache [ file ]. seekPos = FileUnknownPos ;
1585
+ vfdP -> seekPos = FileUnknownPos ;
1517
1586
}
1518
1587
1519
1588
return returnCode ;
@@ -1539,7 +1608,7 @@ FileSync(File file)
1539
1608
off_t
1540
1609
FileSeek (File file , off_t offset , int whence )
1541
1610
{
1542
- int returnCode ;
1611
+ Vfd * vfdP ;
1543
1612
1544
1613
Assert (FileIsValid (file ));
1545
1614
@@ -1548,25 +1617,33 @@ FileSeek(File file, off_t offset, int whence)
1548
1617
(int64 ) VfdCache [file ].seekPos ,
1549
1618
(int64 ) offset , whence ));
1550
1619
1620
+ vfdP = & VfdCache [file ];
1621
+
1551
1622
if (FileIsNotOpen (file ))
1552
1623
{
1553
1624
switch (whence )
1554
1625
{
1555
1626
case SEEK_SET :
1556
1627
if (offset < 0 )
1557
- elog (ERROR , "invalid seek offset: " INT64_FORMAT ,
1558
- (int64 ) offset );
1559
- VfdCache [file ].seekPos = offset ;
1628
+ {
1629
+ errno = EINVAL ;
1630
+ return (off_t ) - 1 ;
1631
+ }
1632
+ vfdP -> seekPos = offset ;
1560
1633
break ;
1561
1634
case SEEK_CUR :
1562
- VfdCache [file ].seekPos += offset ;
1635
+ if (FilePosIsUnknown (vfdP -> seekPos ) ||
1636
+ vfdP -> seekPos + offset < 0 )
1637
+ {
1638
+ errno = EINVAL ;
1639
+ return (off_t ) - 1 ;
1640
+ }
1641
+ vfdP -> seekPos += offset ;
1563
1642
break ;
1564
1643
case SEEK_END :
1565
- returnCode = FileAccess (file );
1566
- if (returnCode < 0 )
1567
- return returnCode ;
1568
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1569
- offset , whence );
1644
+ if (FileAccess (file ) < 0 )
1645
+ return (off_t ) - 1 ;
1646
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1570
1647
break ;
1571
1648
default :
1572
1649
elog (ERROR , "invalid whence: %d" , whence );
@@ -1579,27 +1656,27 @@ FileSeek(File file, off_t offset, int whence)
1579
1656
{
1580
1657
case SEEK_SET :
1581
1658
if (offset < 0 )
1582
- elog (ERROR , "invalid seek offset: " INT64_FORMAT ,
1583
- (int64 ) offset );
1584
- if (VfdCache [file ].seekPos != offset )
1585
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1586
- offset , whence );
1659
+ {
1660
+ errno = EINVAL ;
1661
+ return (off_t ) - 1 ;
1662
+ }
1663
+ if (vfdP -> seekPos != offset )
1664
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1587
1665
break ;
1588
1666
case SEEK_CUR :
1589
- if (offset != 0 || VfdCache [file ].seekPos == FileUnknownPos )
1590
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1591
- offset , whence );
1667
+ if (offset != 0 || FilePosIsUnknown (vfdP -> seekPos ))
1668
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1592
1669
break ;
1593
1670
case SEEK_END :
1594
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1595
- offset , whence );
1671
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1596
1672
break ;
1597
1673
default :
1598
1674
elog (ERROR , "invalid whence: %d" , whence );
1599
1675
break ;
1600
1676
}
1601
1677
}
1602
- return VfdCache [file ].seekPos ;
1678
+
1679
+ return vfdP -> seekPos ;
1603
1680
}
1604
1681
1605
1682
/*
0 commit comments