Thread: RE: [HACKERS] Recovery on incomplete write

RE: [HACKERS] Recovery on incomplete write

From
"Hiroshi Inoue"
Date:
>
> > -----Original Message-----
> > From: Bruce Momjian [mailto:maillist@candle.pha.pa.us]
> > Sent: Tuesday, September 28, 1999 11:54 PM
> > To: Tom Lane
> > Cc: Hiroshi Inoue; pgsql-hackers
> > Subject: Re: [HACKERS] Recovery on incomplete write
> >
> >
> > > "Hiroshi Inoue" <Inoue@tpf.co.jp> writes:
> > > > I have wondered that md.c handles incomplete block(page)s
> > > > correctly.
> > > > Am I mistaken ?
> > >
> > > I think you are right, and there may be some other trouble
> spots in that
> > > file too.  I remember thinking that the code depended heavily on never
> > > having a partial block at the end of the file.
> > >
> > > But is it worth fixing?  The only way I can see for the file length
> > > to become funny is if we run out of disk space part way
> through writing
> > > a page, which seems unlikely...
> > >
> >
> > That is how he got started, the TODO item about running out of disk
> > space causing corrupted databases.  I think it needs a fix, if we can.
> >
>
> Maybe it isn't so difficult to fix.
> I would provide a patch.
>

Here is a patch.

1) mdnblocks() ignores a partial block at the end of relation files.
2) mdread() ignores a partial block of block number 0.
3) mdextend() adjusts its position to a multiple of BLCKSZ   before writing.
4) mdextend() truncates extra bytes in case of incomplete write.

If there's no objection,I would commit this change to the current
tree.

Regards.

Hiroshi Inoue
Inoue@tpf.co.jp

*** storage/smgr/md.c.orig    Thu Sep 30 10:50:58 1999
--- storage/smgr/md.c    Tue Oct  5 13:30:55 1999
***************
*** 233,239 **** int mdextend(Relation reln, char *buffer) {
!     long        pos;     int            nblocks;     MdfdVec    *v;

--- 233,239 ---- int mdextend(Relation reln, char *buffer) {
!     long        pos, nbytes;     int            nblocks;     MdfdVec    *v;

***************
*** 243,250 ****     if ((pos = FileSeek(v->mdfd_vfd, 0L, SEEK_END)) < 0)         return SM_FAIL;

!     if (FileWrite(v->mdfd_vfd, buffer, BLCKSZ) != BLCKSZ)         return SM_FAIL;
     /* remember that we did a write, so we can sync at xact commit */     v->mdfd_flags |= MDFD_DIRTY;
--- 243,264 ----     if ((pos = FileSeek(v->mdfd_vfd, 0L, SEEK_END)) < 0)         return SM_FAIL;

!     if (pos % BLCKSZ != 0) /* the last block is incomplete */
!     {
!         pos = BLCKSZ * (long)(pos / BLCKSZ);
!         if (FileSeek(v->mdfd_vfd, pos, SEEK_SET) < 0)
!             return SM_FAIL;
!     }
!
!     if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ)) != BLCKSZ)
!     {
!         if (nbytes > 0)
!         {
!             FileTruncate(v->mdfd_vfd, pos);
!             FileSeek(v->mdfd_vfd, pos, SEEK_SET);
!         }         return SM_FAIL;
+     }
     /* remember that we did a write, so we can sync at xact commit */     v->mdfd_flags |= MDFD_DIRTY;
***************
*** 432,437 ****
--- 446,453 ----     {         if (nbytes == 0)             MemSet(buffer, 0, BLCKSZ);
+         else if (blocknum == 0 && nbytes > 0 && mdnblocks(reln) == 0)
+             MemSet(buffer, 0, BLCKSZ);         else             status = SM_FAIL;     }
***************
*** 1067,1072 **** {     long        len;

!     len = FileSeek(file, 0L, SEEK_END) - 1;
!     return (BlockNumber) ((len < 0) ? 0 : 1 + len / blcksz); }
--- 1083,1088 ---- {     long        len;

!     len = FileSeek(file, 0L, SEEK_END);
!     return (BlockNumber) (len / blcksz); }