Google File System里面有一小节关于文件追加模式是原子操作,笔者不得其解:
l例如现在有两个独立的进程A和B同时append 数据到一个文件里,添加文件必须收lseek文件的末尾的位置,找准位置后才能添加数据:
首先进程A,seek到位置1500byte的位置是文件的末尾
同时进程B,也seek到1500byte
第三,进程B写入100byte的数据,此时文件末尾变成1600byte
第四,调度到A进程时,write数据,由于第一次Alseek到的位置是1500tye,因此A和B写入数据时,实际上已经产生了互相覆盖的可能
1。O_APPEND的含义
是在每次写之前,都讲标志位移动到文件的末端。表面上读这句话可能会有误解,提出一个问题:当在O_APPEND打开后,然后用 lseek移动到其他的位置,然后再用write写,这个时候,请问你数据写到哪里去了?是在末端,还是lseek移动到得位置。答案是在末端,因为 O_APPEND打开后,是一个原子操作:移动到末端,写数据。这是O_APPEND打开的作用。中间的插入是无效的。例如 : int fd = open("test.txt",RDWR O_APPEND); lseek(fd,10,SEEK_SET); if(write(fd,buffer,strlen(buffer)) !=strlen(buffer)){ perror("write error"); exit(1); } read(fd,buffer,20);这里lseek是没有用的,write的写入是到末端的。在write写完后,标志位是在文件末端的,这个时候的 读是不会读的,所以以前的lseek是没有用的,除非你读之前再lseek一次。 这里的read将不会读出 任何数据,因为在末尾。它还是保持原来的写入的数据。
2 在read读出数据的时候,要明白一个问题。read读出的数据大部分情况下,不是以0结尾的。这样就造成了一种情况,你要输出读出数据的时候,就会出现 问题,因为puts,printf函数都是以0作为输出结束符的。就出出现前面的字符是你想看到的,后面的大部分是乱码.而对于fgets等函数,会在末 尾自动加0
很明显可以看出O_APPEND提供了无锁的文件追加方式,这个机制为并发append,提供了好的内核级别的底层支持,因此GFs的原子记录增加的描述是正确的