517
511
info->error= static_cast<int>(left_length); /* We only got this many char */
520
length_local=0; /* Didn't read any chars */
514
length=0; /* Didn't read any chars */
522
else if (( length_local= my_read(info->file,info->buffer, max_length,
516
else if ((length= my_read(info->file,info->buffer, max_length,
523
517
info->myflags)) < Count ||
524
length_local == (size_t) -1)
518
length == (size_t) -1)
526
if ( length_local != (size_t) -1)
527
memcpy(Buffer, info->buffer, length_local);
528
info->pos_in_file= pos_in_file_local;
529
info->error= length_local == (size_t) -1 ? -1 : (int) ( length_local+left_length);
520
if (length != (size_t) -1)
521
memcpy(Buffer, info->buffer, length);
522
info->pos_in_file= pos_in_file;
523
info->error= length == (size_t) -1 ? -1 : (int) (length+left_length);
530
524
info->read_pos=info->read_end=info->buffer;
533
527
info->read_pos=info->buffer+Count;
534
info->read_end=info->buffer+ length_local;
535
info->pos_in_file=pos_in_file_local;
528
info->read_end=info->buffer+length;
529
info->pos_in_file=pos_in_file;
536
530
memcpy(Buffer, info->buffer, Count);
536
Prepare IO_CACHE for shared use.
539
init_io_cache_share()
540
read_cache A read cache. This will be copied for
541
every thread after setup.
543
write_cache If non-NULL a write cache that is to be
544
synchronized with the read caches.
545
num_threads Number of threads sharing the cache
546
including the write thread if any.
550
The shared cache is used so: One IO_CACHE is initialized with
551
init_io_cache(). This includes the allocation of a buffer. Then a
552
share is allocated and init_io_cache_share() is called with the io
553
cache and the share. Then the io cache is copied for each thread. So
554
every thread has its own copy of IO_CACHE. But the allocated buffer
555
is shared because cache->buffer is the same for all caches.
557
One thread reads data from the file into the buffer. All threads
558
read from the buffer, but every thread maintains its own set of
559
pointers into the buffer. When all threads have used up the buffer
560
contents, one of the threads reads the next block of data into the
561
buffer. To accomplish this, each thread enters the cache lock before
562
accessing the buffer. They wait in lock_io_cache() until all threads
563
joined the lock. The last thread entering the lock is in charge of
564
reading from file to buffer. It wakes all threads when done.
566
Synchronizing a write cache to the read caches works so: Whenever
567
the write buffer needs a flush, the write thread enters the lock and
568
waits for all other threads to enter the lock too. They do this when
569
they have used up the read buffer. When all threads are in the lock,
570
the write thread copies the write buffer to the read buffer and
573
share->running_threads is the number of threads not being in the
574
cache lock. When entering lock_io_cache() the number is decreased.
575
When the thread that fills the buffer enters unlock_io_cache() the
576
number is reset to the number of threads. The condition
577
running_threads == 0 means that all threads are in the lock. Bumping
578
up the number to the full count is non-intuitive. But increasing the
579
number by one for each thread that leaves the lock could lead to a
580
solo run of one thread. The last thread to join a lock reads from
581
file to buffer, wakes the other threads, processes the data in the
582
cache and enters the lock again. If no other thread left the lock
583
meanwhile, it would think it's the last one again and read the next
586
The share has copies of 'error', 'buffer', 'read_end', and
587
'pos_in_file' from the thread that filled the buffer. We may not be
588
able to access this information directly from its cache because the
589
thread may be removed from the share before the variables could be
590
copied by all other threads. Or, if a write buffer is synchronized,
591
it would change its 'pos_in_file' after waking the other threads,
592
possibly before they could copy its value.
594
However, the 'buffer' variable in the share is for a synchronized
595
write cache. It needs to know where to put the data. Otherwise it
596
would need access to the read cache of one of the threads that is
597
not yet removed from the share.
603
void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare,
604
IO_CACHE *write_cache, uint32_t num_threads)
606
assert(num_threads > 1);
607
assert(read_cache->type == READ_CACHE);
608
assert(!write_cache || (write_cache->type == WRITE_CACHE));
610
pthread_mutex_init(&cshare->mutex, MY_MUTEX_INIT_FAST);
611
pthread_cond_init(&cshare->cond, 0);
612
pthread_cond_init(&cshare->cond_writer, 0);
614
cshare->running_threads= num_threads;
615
cshare->total_threads= num_threads;
616
cshare->error= 0; /* Initialize. */
617
cshare->buffer= read_cache->buffer;
618
cshare->read_end= NULL; /* See function comment of lock_io_cache(). */
619
cshare->pos_in_file= 0; /* See function comment of lock_io_cache(). */
620
cshare->source_cache= write_cache; /* Can be NULL. */
622
read_cache->share= cshare;
623
read_cache->read_function= _my_b_read_r;
624
read_cache->current_pos= NULL;
625
read_cache->current_end= NULL;
628
write_cache->share= cshare;
635
Remove a thread from shared access to IO_CACHE.
639
cache The IO_CACHE to be removed from the share.
643
Every thread must do that on exit for not to deadlock other threads.
645
The last thread destroys the pthread resources.
647
A writer flushes its cache first.
653
void remove_io_thread(IO_CACHE *cache)
655
IO_CACHE_SHARE *cshare= cache->share;
658
/* If the writer goes, it needs to flush the write cache. */
659
if (cache == cshare->source_cache)
660
flush_io_cache(cache);
662
pthread_mutex_lock(&cshare->mutex);
664
/* Remove from share. */
665
total= --cshare->total_threads;
667
/* Detach from share. */
670
/* If the writer goes, let the readers know. */
671
if (cache == cshare->source_cache)
673
cshare->source_cache= NULL;
676
/* If all threads are waiting for me to join the lock, wake them. */
677
if (!--cshare->running_threads)
679
pthread_cond_signal(&cshare->cond_writer);
680
pthread_cond_broadcast(&cshare->cond);
683
pthread_mutex_unlock(&cshare->mutex);
687
pthread_cond_destroy (&cshare->cond_writer);
688
pthread_cond_destroy (&cshare->cond);
689
pthread_mutex_destroy(&cshare->mutex);
697
Lock IO cache and wait for all other threads to join.
701
cache The cache of the thread entering the lock.
702
pos File position of the block to read.
703
Unused for the write thread.
707
Wait for all threads to finish with the current buffer. We want
708
all threads to proceed in concert. The last thread to join
709
lock_io_cache() will read the block from file and all threads start
710
to use it. Then they will join again for reading the next block.
712
The waiting threads detect a fresh buffer by comparing
713
cshare->pos_in_file with the position they want to process next.
714
Since the first block may start at position 0, we take
715
cshare->read_end as an additional condition. This variable is
716
initialized to NULL and will be set after a block of data is written
720
1 OK, lock in place, go ahead and read.
721
0 OK, unlocked, another thread did the read.
724
static int lock_io_cache(IO_CACHE *cache, my_off_t pos)
726
IO_CACHE_SHARE *cshare= cache->share;
728
/* Enter the lock. */
729
pthread_mutex_lock(&cshare->mutex);
730
cshare->running_threads--;
732
if (cshare->source_cache)
734
/* A write cache is synchronized to the read caches. */
736
if (cache == cshare->source_cache)
738
/* The writer waits until all readers are here. */
739
while (cshare->running_threads)
741
pthread_cond_wait(&cshare->cond_writer, &cshare->mutex);
743
/* Stay locked. Leave the lock later by unlock_io_cache(). */
747
/* The last thread wakes the writer. */
748
if (!cshare->running_threads)
750
pthread_cond_signal(&cshare->cond_writer);
754
Readers wait until the data is copied from the writer. Another
755
reason to stop waiting is the removal of the write thread. If this
756
happens, we leave the lock with old data in the buffer.
758
while ((!cshare->read_end || (cshare->pos_in_file < pos)) &&
759
cshare->source_cache)
761
pthread_cond_wait(&cshare->cond, &cshare->mutex);
765
If the writer was removed from the share while this thread was
766
asleep, we need to simulate an EOF condition. The writer cannot
767
reset the share variables as they might still be in use by readers
768
of the last block. When we awake here then because the last
769
joining thread signalled us. If the writer is not the last, it
770
will not signal. So it is safe to clear the buffer here.
772
if (!cshare->read_end || (cshare->pos_in_file < pos))
774
cshare->read_end= cshare->buffer; /* Empty buffer. */
775
cshare->error= 0; /* EOF is not an error. */
781
There are read caches only. The last thread arriving in
782
lock_io_cache() continues with a locked cache and reads the block.
784
if (!cshare->running_threads)
786
/* Stay locked. Leave the lock later by unlock_io_cache(). */
791
All other threads wait until the requested block is read by the
792
last thread arriving. Another reason to stop waiting is the
793
removal of a thread. If this leads to all threads being in the
794
lock, we have to continue also. The first of the awaken threads
795
will then do the read.
797
while ((!cshare->read_end || (cshare->pos_in_file < pos)) &&
798
cshare->running_threads)
800
pthread_cond_wait(&cshare->cond, &cshare->mutex);
803
/* If the block is not yet read, continue with a locked cache and read. */
804
if (!cshare->read_end || (cshare->pos_in_file < pos))
806
/* Stay locked. Leave the lock later by unlock_io_cache(). */
810
/* Another thread did read the block already. */
814
Leave the lock. Do not call unlock_io_cache() later. The thread that
815
filled the buffer did this and marked all threads as running.
817
pthread_mutex_unlock(&cshare->mutex);
827
cache The cache of the thread leaving the lock.
830
This is called by the thread that filled the buffer. It marks all
831
threads as running and awakes them. This must not be done by any
834
Do not signal cond_writer. Either there is no writer or the writer
835
is the only one who can call this function.
837
The reason for resetting running_threads to total_threads before
838
waking all other threads is that it could be possible that this
839
thread is so fast with processing the buffer that it enters the lock
840
before even one other thread has left it. If every awoken thread
841
would increase running_threads by one, this thread could think that
842
he is again the last to join and would not wait for the other
843
threads to process the data.
849
static void unlock_io_cache(IO_CACHE *cache)
851
IO_CACHE_SHARE *cshare= cache->share;
853
cshare->running_threads= cshare->total_threads;
854
pthread_cond_broadcast(&cshare->cond);
855
pthread_mutex_unlock(&cshare->mutex);
861
Read from IO_CACHE when it is shared between several threads.
865
cache IO_CACHE pointer
866
Buffer Buffer to retrieve count bytes from file
867
Count Number of bytes to read into Buffer
870
This function is only called from the my_b_read() macro when there
871
isn't enough characters in the buffer to satisfy the request.
875
It works as follows: when a thread tries to read from a file (that
876
is, after using all the data from the (shared) buffer), it just
877
hangs on lock_io_cache(), waiting for other threads. When the very
878
last thread attempts a read, lock_io_cache() returns 1, the thread
879
does actual IO and unlock_io_cache(), which signals all the waiting
880
threads that data is in the buffer.
884
When changing this function, be careful with handling file offsets
885
(end-of_file, pos_in_file). Do not cast them to possibly smaller
886
types than my_off_t unless you can be sure that their value fits.
887
Same applies to differences of file offsets. (Bug #11527)
889
When changing this function, check _my_b_read(). It might need the
893
0 we succeeded in reading all data
894
1 Error: can't read requested characters
897
extern "C" int _my_b_read_r(register IO_CACHE *cache, unsigned char *Buffer, size_t Count)
899
my_off_t pos_in_file;
900
size_t length, diff_length, left_length;
901
IO_CACHE_SHARE *cshare= cache->share;
903
if ((left_length= (size_t) (cache->read_end - cache->read_pos)))
905
assert(Count >= left_length); /* User is not using my_b_read() */
906
memcpy(Buffer, cache->read_pos, left_length);
907
Buffer+= left_length;
914
pos_in_file= cache->pos_in_file + (cache->read_end - cache->buffer);
915
diff_length= (size_t) (pos_in_file & (IO_SIZE-1));
916
length=IO_ROUND_UP(Count+diff_length)-diff_length;
917
length= ((length <= cache->read_length) ?
918
length + IO_ROUND_DN(cache->read_length - length) :
919
length - IO_ROUND_UP(length - cache->read_length));
920
if (cache->type != READ_FIFO &&
921
(length > (cache->end_of_file - pos_in_file)))
922
length= (size_t) (cache->end_of_file - pos_in_file);
925
cache->error= (int) left_length;
928
if (lock_io_cache(cache, pos_in_file))
930
/* With a synchronized write/read cache we won't come here... */
931
assert(!cshare->source_cache);
933
... unless the writer has gone before this thread entered the
934
lock. Simulate EOF in this case. It can be distinguished by
942
Whenever a function which operates on IO_CACHE flushes/writes
943
some part of the IO_CACHE to disk it will set the property
944
"seek_not_done" to indicate this to other functions operating
947
if (cache->seek_not_done)
949
if (lseek(cache->file, pos_in_file, SEEK_SET) == MY_FILEPOS_ERROR)
952
unlock_io_cache(cache);
956
len= my_read(cache->file, cache->buffer, length, cache->myflags);
958
cache->read_end= cache->buffer + (len == (size_t) -1 ? 0 : len);
959
cache->error= (len == length ? 0 : (int) len);
960
cache->pos_in_file= pos_in_file;
962
/* Copy important values to the share. */
963
cshare->error= cache->error;
964
cshare->read_end= cache->read_end;
965
cshare->pos_in_file= pos_in_file;
967
/* Mark all threads as running and wake them. */
968
unlock_io_cache(cache);
973
With a synchronized write/read cache readers always come here.
974
Copy important values from the share.
976
cache->error= cshare->error;
977
cache->read_end= cshare->read_end;
978
cache->pos_in_file= cshare->pos_in_file;
980
len= ((cache->error == -1) ? (size_t) -1 :
981
(size_t) (cache->read_end - cache->buffer));
983
cache->read_pos= cache->buffer;
984
cache->seek_not_done= 0;
985
if (len == 0 || len == (size_t) -1)
987
cache->error= (int) left_length;
990
cnt= (len > Count) ? Count : len;
991
memcpy(Buffer, cache->read_pos, cnt);
995
cache->read_pos+= cnt;
1002
Copy data from write cache to read cache.
1005
copy_to_read_buffer()
1006
write_cache The write cache.
1007
write_buffer The source of data, mostly the cache buffer.
1008
write_length The number of bytes to copy.
1011
The write thread will wait for all read threads to join the cache
1012
lock. Then it copies the data over and wakes the read threads.
1018
static void copy_to_read_buffer(IO_CACHE *write_cache,
1019
const unsigned char *write_buffer, size_t write_length)
1021
IO_CACHE_SHARE *cshare= write_cache->share;
1023
assert(cshare->source_cache == write_cache);
1025
write_length is usually less or equal to buffer_length.
1026
It can be bigger if _my_b_write() is called with a big length.
1028
while (write_length)
1030
size_t copy_length= min(write_length, write_cache->buffer_length);
1033
rc= lock_io_cache(write_cache, write_cache->pos_in_file);
1034
/* The writing thread does always have the lock when it awakes. */
1037
memcpy(cshare->buffer, write_buffer, copy_length);
1040
cshare->read_end= cshare->buffer + copy_length;
1041
cshare->pos_in_file= write_cache->pos_in_file;
1043
/* Mark all threads as running and wake them. */
1044
unlock_io_cache(write_cache);
1046
write_buffer+= copy_length;
1047
write_length-= copy_length;
1053
Do sequential read from the SEQ_READ_APPEND cache.
1055
We do this in three stages:
1056
- first read from info->buffer
1057
- then if there are still data to read, try the file descriptor
1058
- afterwards, if there are still data to read, try append buffer
1065
extern "C" int _my_b_seq_read(register IO_CACHE *info, unsigned char *Buffer, size_t Count)
1067
size_t length, diff_length, left_length, save_count, max_length;
1068
my_off_t pos_in_file;
1071
/* first, read the regular buffer */
1072
if ((left_length=(size_t) (info->read_end-info->read_pos)))
1074
assert(Count > left_length); /* User is not using my_b_read() */
1075
memcpy(Buffer,info->read_pos, left_length);
1076
Buffer+=left_length;
1079
lock_append_buffer(info);
1081
/* pos_in_file always point on where info->buffer was read */
1082
if ((pos_in_file=info->pos_in_file +
1083
(size_t) (info->read_end - info->buffer)) >= info->end_of_file)
1084
goto read_append_buffer;
1087
With read-append cache we must always do a seek before we read,
1088
because the write could have moved the file pointer astray
1090
if (lseek(info->file,pos_in_file,SEEK_SET) == MY_FILEPOS_ERROR)
1093
unlock_append_buffer(info);
1096
info->seek_not_done=0;
1098
diff_length= (size_t) (pos_in_file & (IO_SIZE-1));
1100
/* now the second stage begins - read from file descriptor */
1101
if (Count >= (size_t) (IO_SIZE+(IO_SIZE-diff_length)))
1103
/* Fill first intern buffer */
1106
length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
1107
if ((read_length= my_read(info->file,Buffer, length,
1108
info->myflags)) == (size_t) -1)
1111
unlock_append_buffer(info);
1115
Buffer+=read_length;
1116
pos_in_file+=read_length;
1118
if (read_length != length)
1121
We only got part of data; Read the rest of the data from the
1124
goto read_append_buffer;
1126
left_length+=length;
1130
max_length= info->read_length-diff_length;
1131
if (max_length > (info->end_of_file - pos_in_file))
1132
max_length= (size_t) (info->end_of_file - pos_in_file);
1136
goto read_append_buffer;
1137
length=0; /* Didn't read any more chars */
1141
length= my_read(info->file,info->buffer, max_length, info->myflags);
1142
if (length == (size_t) -1)
1145
unlock_append_buffer(info);
1150
memcpy(Buffer, info->buffer, length);
1155
added the line below to make
1156
assert(pos_in_file==info->end_of_file) pass.
1157
otherwise this does not appear to be needed
1159
pos_in_file += length;
1160
goto read_append_buffer;
1163
unlock_append_buffer(info);
1164
info->read_pos=info->buffer+Count;
1165
info->read_end=info->buffer+length;
1166
info->pos_in_file=pos_in_file;
1167
memcpy(Buffer,info->buffer,(size_t) Count);
1173
Read data from the current write buffer.
1174
Count should never be == 0 here (The code will work even if count is 0)
1178
/* First copy the data to Count */
1179
size_t len_in_buff = (size_t) (info->write_pos - info->append_read_pos);
1181
size_t transfer_len;
1183
assert(info->append_read_pos <= info->write_pos);
1185
TODO: figure out if the assert below is needed or correct.
1187
assert(pos_in_file == info->end_of_file);
1188
copy_len=min(Count, len_in_buff);
1189
memcpy(Buffer, info->append_read_pos, copy_len);
1190
info->append_read_pos += copy_len;
1193
info->error = static_cast<int>(save_count - Count);
1195
/* Fill read buffer with data from write buffer */
1196
memcpy(info->buffer, info->append_read_pos,
1197
(size_t) (transfer_len=len_in_buff - copy_len));
1198
info->read_pos= info->buffer;
1199
info->read_end= info->buffer+transfer_len;
1200
info->append_read_pos=info->write_pos;
1201
info->pos_in_file=pos_in_file+copy_len;
1202
info->end_of_file+=len_in_buff;
1204
unlock_append_buffer(info);
1205
return Count ? 1 : 0;
541
1209
#ifdef HAVE_AIOWAIT
545
* Read from the st_io_cache into a buffer and feed asynchronously from disk when needed.
547
* @param info st_io_cache pointer
548
* @param Buffer Buffer to retrieve count bytes from file
549
* @param Count Number of bytes to read into Buffer
551
* @retval -1 An error has occurred; errno is set.
553
* @retval 1 An error has occurred; st_io_cache to error state.
555
int _my_b_async_read(register st_io_cache *info, unsigned char *Buffer, size_t Count)
1212
Read from the IO_CACHE into a buffer and feed asynchronously
1213
from disk when needed.
1217
info IO_CACHE pointer
1218
Buffer Buffer to retrieve count bytes from file
1219
Count Number of bytes to read into Buffer
1222
-1 An error has occurred; my_errno is set.
1224
1 An error has occurred; IO_CACHE to error state.
1227
int _my_b_async_read(register IO_CACHE *info, unsigned char *Buffer, size_t Count)
557
size_t length_local,read_length,diff_length,left_length,use_length,org_Count;
1229
size_t length,read_length,diff_length,left_length,use_length,org_Count;
558
1230
size_t max_length;
559
1231
my_off_t next_pos_in_file;
560
1232
unsigned char *read_buffer;
909
unlock_append_buffer(info, need_append_buffer_lock);
1620
UNLOCK_APPEND_BUFFER;
915
* Free an st_io_cache object
918
* It's currently safe to call this if one has called init_io_cache()
919
* on the 'info' object, even if init_io_cache() failed.
920
* This function is also safe to call twice with the same handle.
922
* @param info st_io_cache Handle to free
927
int st_io_cache::end_io_cache()
1625
Free an IO_CACHE object
1629
info IO_CACHE Handle to free
1632
It's currently safe to call this if one has called init_io_cache()
1633
on the 'info' object, even if init_io_cache() failed.
1634
This function is also safe to call twice with the same handle.
1641
int end_io_cache(IO_CACHE *info)
938
if (type == READ_CACHE)
939
global_read_buffer.sub(buffer_length);
941
if (file != -1) /* File doesn't exist */
942
_error= my_b_flush_io_cache(this, 1);
943
free((unsigned char*) buffer);
944
buffer=read_pos=(unsigned char*) 0;
1644
IO_CACHE_CALLBACK pre_close;
1647
Every thread must call remove_io_thread(). The last one destroys
1650
assert(!info->share || !info->share->total_threads);
1652
if ((pre_close=info->pre_close))
1657
if (info->alloced_buffer)
1659
info->alloced_buffer=0;
1660
if (info->file != -1) /* File doesn't exist */
1661
error= my_b_flush_io_cache(info,1);
1662
free((unsigned char*) info->buffer);
1663
info->buffer=info->read_pos=(unsigned char*) 0;
1665
if (info->type == SEQ_READ_APPEND)
1667
/* Destroy allocated mutex */
1668
info->type= TYPE_NOT_SET;
1669
pthread_mutex_destroy(&info->append_buffer_lock);
948
1672
} /* end_io_cache */
950
} /* namespace internal */
951
} /* namespace drizzled */
1675
/**********************************************************************
1676
Testing of MF_IOCACHE
1677
**********************************************************************/
1683
void die(const char* fmt, ...)
1686
va_start(va_args,fmt);
1687
fprintf(stderr,"Error:");
1688
vfprintf(stderr, fmt,va_args);
1689
fprintf(stderr,", errno=%d\n", errno);
1693
int open_file(const char* fname, IO_CACHE* info, int cache_size)
1696
if ((fd=my_open(fname,O_CREAT | O_RDWR,MYF(MY_WME))) < 0)
1697
die("Could not open %s", fname);
1698
if (init_io_cache(info, fd, cache_size, SEQ_READ_APPEND, 0,0,MYF(MY_WME)))
1699
die("failed in init_io_cache()");
1703
void close_file(IO_CACHE* info)
1706
my_close(info->file, MYF(MY_WME));
1709
int main(int argc, char** argv)
1711
IO_CACHE sra_cache; /* SEQ_READ_APPEND */
1713
const char* fname="/tmp/iocache.test";
1714
int cache_size=16384;
1716
int max_block,total_bytes=0;
1717
int i,num_loops=100,error=0;
1719
char* block, *block_end;
1721
max_block = cache_size*3;
1722
if (!(block=(char*)malloc(max_block)))
1723
die("Not enough memory to allocate test block");
1724
block_end = block + max_block;
1725
for (p = block,i=0; p < block_end;i++)
1729
if (my_stat(fname,&status, MYF(0)) &&
1730
my_delete(fname,MYF(MY_WME)))
1732
die("Delete of %s failed, aborting", fname);
1734
open_file(fname,&sra_cache, cache_size);
1735
for (i = 0; i < num_loops; i++)
1738
int block_size = abs(rand() % max_block);
1739
int4store(buf, block_size);
1740
if (my_b_append(&sra_cache,buf,4) ||
1741
my_b_append(&sra_cache, block, block_size))
1742
die("write failed");
1743
total_bytes += 4+block_size;
1745
close_file(&sra_cache);
1747
if (!my_stat(fname,&status,MYF(MY_WME)))
1748
die("%s failed to stat, but I had just closed it,\
1749
wonder how that happened");
1750
printf("Final size of %s is %s, wrote %d bytes\n",fname,
1751
llstr(status.st_size,llstr_buf),
1753
my_delete(fname, MYF(MY_WME));
1754
/* check correctness of tests */
1755
if (total_bytes != status.st_size)
1757
fprintf(stderr,"Not the same number of bytes acutally in file as bytes \
1758
supposedly written\n");