@@ -153,7 +153,14 @@ int max_safe_fds = 32; /* default if not changed */
153
153
154
154
#define FileIsNotOpen (file ) (VfdCache[file].fd == VFD_CLOSED)
155
155
156
+ /*
157
+ * Note: a VFD's seekPos is normally always valid, but if for some reason
158
+ * an lseek() fails, it might become set to FileUnknownPos. We can struggle
159
+ * along without knowing the seek position in many cases, but in some places
160
+ * we have to fail if we don't have it.
161
+ */
156
162
#define FileUnknownPos ((off_t) -1)
163
+ #define FilePosIsUnknown (pos ) ((pos) < 0)
157
164
158
165
/* these are the assigned bits in fdstate below: */
159
166
#define FD_TEMPORARY (1 << 0) /* T = delete when closed */
@@ -167,7 +174,7 @@ typedef struct vfd
167
174
File nextFree ; /* link to next free VFD, if in freelist */
168
175
File lruMoreRecently ; /* doubly linked recency-of-use list */
169
176
File lruLessRecently ;
170
- off_t seekPos ; /* current logical file position */
177
+ off_t seekPos ; /* current logical file position, or -1 */
171
178
off_t fileSize ; /* current size of file (0 if not temporary) */
172
179
char * fileName ; /* name of file, or NULL for unused VFD */
173
180
/* NB: fileName is malloc'd, and must be free'd when closing the VFD */
@@ -826,19 +833,33 @@ LruDelete(File file)
826
833
827
834
vfdP = & VfdCache [file ];
828
835
829
- /* delete the vfd record from the LRU ring */
830
- Delete (file );
831
-
832
- /* save the seek position */
833
- vfdP -> seekPos = lseek (vfdP -> fd , (off_t ) 0 , SEEK_CUR );
834
- Assert (vfdP -> seekPos != (off_t ) - 1 );
836
+ /*
837
+ * Normally we should know the seek position, but if for some reason we
838
+ * have lost track of it, try again to get it. If we still can't get it,
839
+ * we have a problem: we will be unable to restore the file seek position
840
+ * when and if the file is re-opened. But we can't really throw an error
841
+ * and refuse to close the file, or activities such as transaction cleanup
842
+ * will be broken.
843
+ */
844
+ if (FilePosIsUnknown (vfdP -> seekPos ))
845
+ {
846
+ vfdP -> seekPos = lseek (vfdP -> fd , (off_t ) 0 , SEEK_CUR );
847
+ if (FilePosIsUnknown (vfdP -> seekPos ))
848
+ elog (LOG , "could not seek file \"%s\" before closing: %m" ,
849
+ vfdP -> fileName );
850
+ }
835
851
836
- /* close the file */
852
+ /*
853
+ * Close the file. We aren't expecting this to fail; if it does, better
854
+ * to leak the FD than to mess up our internal state.
855
+ */
837
856
if (close (vfdP -> fd ))
838
- elog (ERROR , "could not close file \"%s\": %m" , vfdP -> fileName );
839
-
840
- -- nfile ;
857
+ elog (LOG , "could not close file \"%s\": %m" , vfdP -> fileName );
841
858
vfdP -> fd = VFD_CLOSED ;
859
+ -- nfile ;
860
+
861
+ /* delete the vfd record from the LRU ring */
862
+ Delete (file );
842
863
}
843
864
844
865
static void
@@ -889,22 +910,39 @@ LruInsert(File file)
889
910
vfdP -> fileMode );
890
911
if (vfdP -> fd < 0 )
891
912
{
892
- DO_DB (elog (LOG , "RE_OPEN FAILED : %d" , errno ));
913
+ DO_DB (elog (LOG , "re-open failed : %m" ));
893
914
return -1 ;
894
915
}
895
916
else
896
917
{
897
- DO_DB (elog (LOG , "RE_OPEN SUCCESS" ));
898
918
++ nfile ;
899
919
}
900
920
901
- /* seek to the right position */
921
+ /*
922
+ * Seek to the right position. We need no special case for seekPos
923
+ * equal to FileUnknownPos, as lseek() will certainly reject that
924
+ * (thus completing the logic noted in LruDelete() that we will fail
925
+ * to re-open a file if we couldn't get its seek position before
926
+ * closing).
927
+ */
902
928
if (vfdP -> seekPos != (off_t ) 0 )
903
929
{
904
- off_t returnValue PG_USED_FOR_ASSERTS_ONLY ;
905
-
906
- returnValue = lseek (vfdP -> fd , vfdP -> seekPos , SEEK_SET );
907
- Assert (returnValue != (off_t ) - 1 );
930
+ if (lseek (vfdP -> fd , vfdP -> seekPos , SEEK_SET ) < 0 )
931
+ {
932
+ /*
933
+ * If we fail to restore the seek position, treat it like an
934
+ * open() failure.
935
+ */
936
+ int save_errno = errno ;
937
+
938
+ elog (LOG , "could not seek file \"%s\" after re-opening: %m" ,
939
+ vfdP -> fileName );
940
+ (void ) close (vfdP -> fd );
941
+ vfdP -> fd = VFD_CLOSED ;
942
+ -- nfile ;
943
+ errno = save_errno ;
944
+ return -1 ;
945
+ }
908
946
}
909
947
}
910
948
@@ -1287,15 +1325,15 @@ FileClose(File file)
1287
1325
1288
1326
if (!FileIsNotOpen (file ))
1289
1327
{
1290
- /* remove the file from the lru ring */
1291
- Delete (file );
1292
-
1293
1328
/* close the file */
1294
1329
if (close (vfdP -> fd ))
1295
- elog (ERROR , "could not close file \"%s\": %m" , vfdP -> fileName );
1330
+ elog (LOG , "could not close file \"%s\": %m" , vfdP -> fileName );
1296
1331
1297
1332
-- nfile ;
1298
1333
vfdP -> fd = VFD_CLOSED ;
1334
+
1335
+ /* remove the file from the lru ring */
1336
+ Delete (file );
1299
1337
}
1300
1338
1301
1339
/*
@@ -1400,6 +1438,7 @@ int
1400
1438
FileRead (File file , char * buffer , int amount )
1401
1439
{
1402
1440
int returnCode ;
1441
+ Vfd * vfdP ;
1403
1442
1404
1443
Assert (FileIsValid (file ));
1405
1444
@@ -1412,11 +1451,17 @@ FileRead(File file, char *buffer, int amount)
1412
1451
if (returnCode < 0 )
1413
1452
return returnCode ;
1414
1453
1454
+ vfdP = & VfdCache [file ];
1455
+
1415
1456
retry :
1416
- returnCode = read (VfdCache [ file ]. fd , buffer , amount );
1457
+ returnCode = read (vfdP -> fd , buffer , amount );
1417
1458
1418
1459
if (returnCode >= 0 )
1419
- VfdCache [file ].seekPos += returnCode ;
1460
+ {
1461
+ /* if seekPos is unknown, leave it that way */
1462
+ if (!FilePosIsUnknown (vfdP -> seekPos ))
1463
+ vfdP -> seekPos += returnCode ;
1464
+ }
1420
1465
else
1421
1466
{
1422
1467
/*
@@ -1445,7 +1490,7 @@ FileRead(File file, char *buffer, int amount)
1445
1490
goto retry ;
1446
1491
1447
1492
/* Trouble, so assume we don't know the file position anymore */
1448
- VfdCache [ file ]. seekPos = FileUnknownPos ;
1493
+ vfdP -> seekPos = FileUnknownPos ;
1449
1494
}
1450
1495
1451
1496
return returnCode ;
@@ -1455,6 +1500,7 @@ int
1455
1500
FileWrite (File file , char * buffer , int amount )
1456
1501
{
1457
1502
int returnCode ;
1503
+ Vfd * vfdP ;
1458
1504
1459
1505
Assert (FileIsValid (file ));
1460
1506
@@ -1467,6 +1513,8 @@ FileWrite(File file, char *buffer, int amount)
1467
1513
if (returnCode < 0 )
1468
1514
return returnCode ;
1469
1515
1516
+ vfdP = & VfdCache [file ];
1517
+
1470
1518
/*
1471
1519
* If enforcing temp_file_limit and it's a temp file, check to see if the
1472
1520
* write would overrun temp_file_limit, and throw error if so. Note: it's
@@ -1475,15 +1523,28 @@ FileWrite(File file, char *buffer, int amount)
1475
1523
* message if we do that. All current callers would just throw error
1476
1524
* immediately anyway, so this is safe at present.
1477
1525
*/
1478
- if (temp_file_limit >= 0 && (VfdCache [ file ]. fdstate & FD_TEMPORARY ))
1526
+ if (temp_file_limit >= 0 && (vfdP -> fdstate & FD_TEMPORARY ))
1479
1527
{
1480
- off_t newPos = VfdCache [ file ]. seekPos + amount ;
1528
+ off_t newPos ;
1481
1529
1482
- if (newPos > VfdCache [file ].fileSize )
1530
+ /*
1531
+ * Normally we should know the seek position, but if for some reason
1532
+ * we have lost track of it, try again to get it. Here, it's fine to
1533
+ * throw an error if we still can't get it.
1534
+ */
1535
+ if (FilePosIsUnknown (vfdP -> seekPos ))
1536
+ {
1537
+ vfdP -> seekPos = lseek (vfdP -> fd , (off_t ) 0 , SEEK_CUR );
1538
+ if (FilePosIsUnknown (vfdP -> seekPos ))
1539
+ elog (ERROR , "could not seek file \"%s\": %m" , vfdP -> fileName );
1540
+ }
1541
+
1542
+ newPos = vfdP -> seekPos + amount ;
1543
+ if (newPos > vfdP -> fileSize )
1483
1544
{
1484
1545
uint64 newTotal = temporary_files_size ;
1485
1546
1486
- newTotal += newPos - VfdCache [ file ]. fileSize ;
1547
+ newTotal += newPos - vfdP -> fileSize ;
1487
1548
if (newTotal > (uint64 ) temp_file_limit * (uint64 ) 1024 )
1488
1549
ereport (ERROR ,
1489
1550
(errcode (ERRCODE_CONFIGURATION_LIMIT_EXCEEDED ),
@@ -1494,25 +1555,33 @@ FileWrite(File file, char *buffer, int amount)
1494
1555
1495
1556
retry :
1496
1557
errno = 0 ;
1497
- returnCode = write (VfdCache [ file ]. fd , buffer , amount );
1558
+ returnCode = write (vfdP -> fd , buffer , amount );
1498
1559
1499
1560
/* if write didn't set errno, assume problem is no disk space */
1500
1561
if (returnCode != amount && errno == 0 )
1501
1562
errno = ENOSPC ;
1502
1563
1503
1564
if (returnCode >= 0 )
1504
1565
{
1505
- VfdCache [file ].seekPos += returnCode ;
1566
+ /* if seekPos is unknown, leave it that way */
1567
+ if (!FilePosIsUnknown (vfdP -> seekPos ))
1568
+ vfdP -> seekPos += returnCode ;
1506
1569
1507
- /* maintain fileSize and temporary_files_size if it's a temp file */
1508
- if (VfdCache [file ].fdstate & FD_TEMPORARY )
1570
+ /*
1571
+ * Maintain fileSize and temporary_files_size if it's a temp file.
1572
+ *
1573
+ * If seekPos is -1 (unknown), this will do nothing; but we could only
1574
+ * get here in that state if we're not enforcing temporary_files_size,
1575
+ * so we don't care.
1576
+ */
1577
+ if (vfdP -> fdstate & FD_TEMPORARY )
1509
1578
{
1510
- off_t newPos = VfdCache [ file ]. seekPos ;
1579
+ off_t newPos = vfdP -> seekPos ;
1511
1580
1512
- if (newPos > VfdCache [ file ]. fileSize )
1581
+ if (newPos > vfdP -> fileSize )
1513
1582
{
1514
- temporary_files_size += newPos - VfdCache [ file ]. fileSize ;
1515
- VfdCache [ file ]. fileSize = newPos ;
1583
+ temporary_files_size += newPos - vfdP -> fileSize ;
1584
+ vfdP -> fileSize = newPos ;
1516
1585
}
1517
1586
}
1518
1587
}
@@ -1540,7 +1609,7 @@ FileWrite(File file, char *buffer, int amount)
1540
1609
goto retry ;
1541
1610
1542
1611
/* Trouble, so assume we don't know the file position anymore */
1543
- VfdCache [ file ]. seekPos = FileUnknownPos ;
1612
+ vfdP -> seekPos = FileUnknownPos ;
1544
1613
}
1545
1614
1546
1615
return returnCode ;
@@ -1566,7 +1635,7 @@ FileSync(File file)
1566
1635
off_t
1567
1636
FileSeek (File file , off_t offset , int whence )
1568
1637
{
1569
- int returnCode ;
1638
+ Vfd * vfdP ;
1570
1639
1571
1640
Assert (FileIsValid (file ));
1572
1641
@@ -1575,25 +1644,33 @@ FileSeek(File file, off_t offset, int whence)
1575
1644
(int64 ) VfdCache [file ].seekPos ,
1576
1645
(int64 ) offset , whence ));
1577
1646
1647
+ vfdP = & VfdCache [file ];
1648
+
1578
1649
if (FileIsNotOpen (file ))
1579
1650
{
1580
1651
switch (whence )
1581
1652
{
1582
1653
case SEEK_SET :
1583
1654
if (offset < 0 )
1584
- elog (ERROR , "invalid seek offset: " INT64_FORMAT ,
1585
- (int64 ) offset );
1586
- VfdCache [file ].seekPos = offset ;
1655
+ {
1656
+ errno = EINVAL ;
1657
+ return (off_t ) - 1 ;
1658
+ }
1659
+ vfdP -> seekPos = offset ;
1587
1660
break ;
1588
1661
case SEEK_CUR :
1589
- VfdCache [file ].seekPos += offset ;
1662
+ if (FilePosIsUnknown (vfdP -> seekPos ) ||
1663
+ vfdP -> seekPos + offset < 0 )
1664
+ {
1665
+ errno = EINVAL ;
1666
+ return (off_t ) - 1 ;
1667
+ }
1668
+ vfdP -> seekPos += offset ;
1590
1669
break ;
1591
1670
case SEEK_END :
1592
- returnCode = FileAccess (file );
1593
- if (returnCode < 0 )
1594
- return returnCode ;
1595
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1596
- offset , whence );
1671
+ if (FileAccess (file ) < 0 )
1672
+ return (off_t ) - 1 ;
1673
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1597
1674
break ;
1598
1675
default :
1599
1676
elog (ERROR , "invalid whence: %d" , whence );
@@ -1606,27 +1683,27 @@ FileSeek(File file, off_t offset, int whence)
1606
1683
{
1607
1684
case SEEK_SET :
1608
1685
if (offset < 0 )
1609
- elog (ERROR , "invalid seek offset: " INT64_FORMAT ,
1610
- (int64 ) offset );
1611
- if (VfdCache [file ].seekPos != offset )
1612
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1613
- offset , whence );
1686
+ {
1687
+ errno = EINVAL ;
1688
+ return (off_t ) - 1 ;
1689
+ }
1690
+ if (vfdP -> seekPos != offset )
1691
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1614
1692
break ;
1615
1693
case SEEK_CUR :
1616
- if (offset != 0 || VfdCache [file ].seekPos == FileUnknownPos )
1617
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1618
- offset , whence );
1694
+ if (offset != 0 || FilePosIsUnknown (vfdP -> seekPos ))
1695
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1619
1696
break ;
1620
1697
case SEEK_END :
1621
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1622
- offset , whence );
1698
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1623
1699
break ;
1624
1700
default :
1625
1701
elog (ERROR , "invalid whence: %d" , whence );
1626
1702
break ;
1627
1703
}
1628
1704
}
1629
- return VfdCache [file ].seekPos ;
1705
+
1706
+ return vfdP -> seekPos ;
1630
1707
}
1631
1708
1632
1709
/*
0 commit comments