#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include "lmp.h" /******************************************************/ /* create a new LMP entry (and the file if not exist) */ /******************************************************/ /* output: a newly allocated LMP entry or NULL */ /***********************************************/ LMP_ENTRY *lmp_new(char *filename, int record_size) { LMP_ENTRY nw; LMP_ENTRY *real_nw=NULL; nw.record_size=record_size; nw.fd=open(filename,O_CREAT|O_RDWR,0666); if(nw.fd==-1) { perror("lmp_new - open fails"); return real_nw; } if(flock(nw.fd,LOCK_EX|LOCK_NB)!=-1) { /* the file is locked. 2 cases: */ /* the file is empty and we must create its header */ /* the file is not empty and is already ready to be used */ struct stat st; if(fstat(nw.fd,&st)==-1) { perror("lmp_new - fstat fails"); close(nw.fd); return real_nw; } if(st.st_size==0) { /* we have created the file, we must build its header */ int i; for(i=0;iis_locked!=0)||(lmp->mapped_addr!=NULL)) return 1; flock(lmp->fd,LOCK_EX); lmp->is_locked=1; if(fstat(lmp->fd,&st)==-1) { lmp_unmap_and_unlock(lmp); return 1; } lmp->mapped_size=st.st_size; lmp->mapped_addr=mmap(NULL,lmp->mapped_size,PROT_READ|PROT_WRITE,MAP_SHARED, lmp->fd, 0); if(lmp->mapped_addr==MAP_FAILED) { lmp_unmap_and_unlock(lmp); return 1; } lmp->nb_records=lmp->mapped_size/lmp->record_size; return 0; } /*********************************************/ /* unmap file from memory, it remains locked */ /*********************************************/ void inline lmp_unmap(LMP_ENTRY *lmp) { if(lmp->mapped_addr!=NULL) { munmap(lmp->mapped_addr,lmp->mapped_size); lmp->mapped_addr=NULL; lmp->mapped_size=0; lmp->nb_records=0; } } /**************************************************************/ /* unlock a file. If file is not yet unmapped, it is unmapped */ /**************************************************************/ void lmp_unmap_and_unlock(LMP_ENTRY *lmp) { lmp_unmap(lmp); if(lmp->is_locked) { flock(lmp->fd,LOCK_UN); lmp->is_locked=0; } } /***************************************************************/ /* close file and destroy LMP entry (the file remains present) */ /***************************************************************/ void lmp_close(LMP_ENTRY *lmp) { lmp_unmap_and_unlock(lmp); close(lmp->fd); free(lmp); } /********************************************************************/ /* append the given record to the given LMP. The LMP must be locked */ /* After the call, the LMP remains locked but becomes unmapped */ /********************************************************************/ /* output: 0=ok, 1=error */ /*************************/ int lmp_append_record(LMP_ENTRY *lmp, void *value) { struct stat st; off_t pos; if(lmp->is_locked==0) return 1; lmp_unmap(lmp); if(fstat(lmp->fd,&st)==-1) { perror("lmp_append_record - fstat fails"); return 1; } pos=(st.st_size/lmp->record_size)*lmp->record_size; /* round the position to the last full record */ if(lseek(lmp->fd,pos,SEEK_SET)!=pos) { perror("lmp_append_record - lseek fails"); return 1; } if(write(lmp->fd,value,lmp->record_size)!=lmp->record_size) { perror("lmp_append_record - write fails"); return 1; } return 0; }