Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <math.h>
- #include <errno.h>
- #include <time.h>
- #define FILENAME_DIR "filedir.dat"
- #define FILENAME_INDEX "fileindex.dat"
- #define FILENAME_MASTER "filemaster.dat"
- #define FOPEN_MODE "rb+"
- #define BUCKETS_PER_PAGE 2
- #define INITIAL_DEPTH 2
- extern int errno ;
- typedef struct Register{ //sctruct que será armazenada no arquivo mestre
- unsigned int cpf;
- char name[16];
- char date[16];
- char sex[1];
- }Register;
- typedef struct Directory{
- unsigned int globalDepth; //profundidade global
- unsigned int *directory; //vetor dos valores do diretorio
- }Directory;
- typedef struct Bucket{
- int cpf; //chave primaria
- int masterIndex; //posição do registro no arquivo mestre
- }Bucket;
- typedef struct Index{
- unsigned int localDepth; //profundidade local
- Bucket *buckets; //buckets do indice
- }Index;
- void testPrintError(){
- printf("[%s]",strerror(errno));
- }
- void errorFileNotFound(){
- printf("\nErro! O arquivo nao foi criado. Execute a opcao 1 para cria-lo.\n");
- testPrintError();
- }
- int hash_function(int cpf, int depth){
- return cpf % intpow(2,depth);
- }
- void fillFile(FILE *file, int tam, int val){//preenche o arquivo "file" com o valor "val" repetido "tam" vezes
- //printf("%i\n",val);
- //fseek(file, 0, SEEK_SET);
- for(int i=0;i<tam;i++){
- fputc(val,file);
- }
- }
- void printBytes(char *msg, int bytes){//imprime a quantidade de bytes na tela
- printf("%s: 0x%x (%i) bytes\n",msg,bytes,bytes);
- }
- int getFileSize(FILE *file){
- fseek(file,0,SEEK_END);
- return ftell(file);
- }
- int indexByteSize(){//tamanho de bytes por indice.
- //4 bytes: p
- //8 bytes: cpf e i do bucket (dois inteiros)
- return (4+(8*BUCKETS_PER_PAGE));
- }
- int masterByteSize(){//tamanho de bytes de uma posição no arquivo master
- //4 bytes: CPF
- //16 bytes: name
- //16 bytes: date
- //1 bytes: sex
- return (4+16+16+1);
- }
- Index loadIndex(int i){//carrega o index na posição i
- FILE *file_index=fopen(FILENAME_INDEX,FOPEN_MODE);
- Index ind;
- if(getFileSize(file_index)<=0){//se o arquivo estiver vazio ou não existir
- //errorFileNotFound();
- }else{
- fseek(file_index,i*indexByteSize(),SEEK_SET);
- fread(&ind.localDepth,sizeof(int),1,file_index);//4 bytes: p
- if(ind.localDepth<INITIAL_DEPTH){
- ind.localDepth=INITIAL_DEPTH;
- }
- ind.buckets=malloc(sizeof(Bucket)*BUCKETS_PER_PAGE);
- for(int j=0;j<BUCKETS_PER_PAGE;j++){
- fread(&ind.buckets[j].cpf,sizeof(int),1,file_index);//4 bytes: cpf
- fread(&ind.buckets[j].masterIndex,sizeof(int),1,file_index);//4 bytes: i
- }
- }
- fclose(file_index);
- return ind;
- }
- void saveIndex(Index ind, int pos){//printf("[%i]",ind.localDepth);
- int d;
- FILE *file_index=fopen(FILENAME_INDEX,FOPEN_MODE);
- fseek(file_index,pos*indexByteSize(),SEEK_SET);
- d=fwrite(&ind.localDepth,sizeof(int),1,file_index);
- for(int i=0;i<BUCKETS_PER_PAGE;i++){
- fwrite(&ind.buckets[i].cpf,sizeof(int),1,file_index);
- fwrite(&ind.buckets[i].masterIndex,sizeof(int),1,file_index);
- }//printf("(%i)\n",d);
- fclose(file_index);
- }
- Register loadMaster(int masterIndex){//carrega o arquivo mestre na posição indicada
- FILE *file_master=fopen(FILENAME_MASTER,FOPEN_MODE);
- Register data;//cria um variável do tipo Register
- if(getFileSize(file_master)<=0){//se o arquivo estiver vazio ou não existir
- errorFileNotFound();
- }else{
- fseek(file_master,masterIndex*masterByteSize(),SEEK_SET);//vai até a posição especificada
- fread(&data.cpf,sizeof(unsigned int),1,file_master);//começa leitura dos dados e grava na sctruct
- fread(&data.date,sizeof(char),16,file_master);
- fread(&data.name,sizeof(char),16,file_master);
- fread(&data.sex,sizeof(char),1,file_master);
- }
- fclose(file_master);//fecha o arquivo
- return data;//retorna a struct preechida
- }
- void saveMaster(Register data, int masterIndex){//recebe a struct preenchida e salva na posição especificada
- FILE *file_master=fopen(FILENAME_MASTER,FOPEN_MODE);//abre o arquivo para leitura
- fseek(file_master,masterIndex*masterByteSize(),SEEK_SET);//vai para o final do arquivo
- fwrite(&data.cpf,sizeof(unsigned int),1,file_master);//começa a escrever no final do arquivo
- fwrite(&data.date,sizeof(char),16,file_master);
- fwrite(&data.name,sizeof(char),16,file_master);
- fwrite(&data.sex,sizeof(char),1,file_master);
- fclose(file_master);//fecha o arquivo
- }
- void loadDirectory(Directory *dir){//carrega o vetor de diretórios do arquivo FILENAME_DIR
- //se o arquivo não existir, cria um vetor básico de p=2.
- //o tamanho do arquivo precisa ser uma potência de 2 maior ou igual a 16, senão vai vir valor errado e não vai ser culpa minha.
- FILE *file_dir=fopen(FILENAME_DIR,FOPEN_MODE);
- int n=getFileSize(file_dir);
- if(n<=0){//se o arquivo nao existir, ou se ele estiver vazio...
- errorFileNotFound();
- }else{
- (*dir).directory=malloc(n);//cria o buffer com o mesmo tamanho do arquivo
- n/=sizeof(int);//divide n pelo tamanho de cada inteiro, n agora é a quantidade de inteiros do arquivo
- (*dir).globalDepth=log2(n);//log2 de n é o valor de p, pois 2^p=n
- rewind(file_dir);//coloca a posição atual de leitura no inicio do arquivo
- fread((*dir).directory,sizeof(int),n,file_dir);//lê todos os n numeros presentes no arquivo e os coloca no vetor directory da struct
- }
- fclose(file_dir);//fecha o arquivo
- }
- void saveDirectory(Directory dir){//salva o diretório no arquivo.
- FILE *file_dir=fopen(FILENAME_DIR,"wb");//abre o arquivo de diretório, no modo wb para apagar os dados anteriores
- fwrite(dir.directory,sizeof(int),pow(2,dir.globalDepth),file_dir);//escreve 2^p numeros inteiros no arquivo, estes numeros inteiros sendo o proprio vetor da struct Directory
- fclose(file_dir);//fecha o arquivo
- }
- int intpow(int base, int exponent){//função de potenciação
- //a função pow() retorna 0 em casos aleatórios então eu fiz essa mais básica.
- int ret=1;
- for(int i=0;i<exponent;i++){
- ret*=base;
- }
- return ret;
- }
- void doubleDirectory(Directory *dir){//dobra o diretório de tamanho, repetindo todos os valores da primeira metade na segunda metade.
- int n=pow(2,(*dir).globalDepth);//obtém o tamanho atual do diretorio
- (*dir).globalDepth++; //aumenta em 1 a profundidade
- unsigned int *newDirectory=malloc(n*2*sizeof(int));//cria o vetor do novo diretorio, com o dobro do tamanho anterior
- for(int i=0;i<(n*2);i++){
- newDirectory[i]=(*dir).directory[i%n];//atribui os valores, o "mod n" aqui vai repetir os valores na mesma sequência.
- }
- free((*dir).directory); //libera o diretorio antigo da memoria
- (*dir).directory=newDirectory;//atribui o novo diretorio à variável da struct
- }
- int increaseIndex(){//adiciona um novo índice vazio no arquivo e retorna sua posição.
- FILE *file_index=fopen(FILENAME_INDEX,FOPEN_MODE);//abre
- //fseek(file_index,0,SEEK_END);//posiciona o indicador no ultimo byte escrito do arquivo do índice
- //int pos=ftell(file_index);//como o indicador está no último byte, ftell irá retornar o tamanho total do arquivo, que também será o valor da posição do índice a ser inserido
- int pos=getFileSize(file_index); //isso faz a mesma coisa que as duas linhas comentadas acima
- int size=indexByteSize();//busca o tamanho de bytes de cada índice
- for(int i=0;i<size;i++){
- fputc(0,file_index);//adiciona bytes 00 no arquivo até dar o tamaho de um índice
- }
- fclose(file_index);//fecha
- pos/=size;//divide o tamanho total anterior pelo tamanho de bytes de cada índice, para obter a posição do registro novo
- return pos;
- }
- void testPrintArray(int *array,int n){//exibe os valores de um array int na tela, usado para testes
- printf("\nARRAY[%i]: [",n);
- for(int i=0;i<n;i++){
- printf("%i,",array[i]);
- }
- printf("]\n");
- }
- int getEmptyBucketPosition(Index ind){//busca pela posição do primeiro bucket do vetor de buckets do indice que estiver vazio.
- //retorna -1 se não achar
- //printf("\ngetEmptyBucketPositionk:::");
- for(int i=0;i<BUCKETS_PER_PAGE;i++){
- //printf("\nbucket[%i].cpf=%i",i,ind.buckets[i].cpf);
- if(ind.buckets[i].cpf==0){
- return i;
- }
- }
- return -1;
- }
- int getRegisterPosition(int cpf, Index ind){
- for(int i=0;i<BUCKETS_PER_PAGE;i++){
- if(ind.buckets[i].cpf==cpf){
- return i;
- }
- }
- return -1;
- }
- void createFiles(){
- //diretório
- printf("Criando arquivo %s...\n",FILENAME_DIR);
- FILE *file_dir=file_dir=fopen(FILENAME_DIR,"wb+");
- for(int i=0;i<4;i++){
- fwrite(&i,sizeof(int),1,file_dir);
- }
- int byteSize=getFileSize(file_dir);
- fclose(file_dir);
- printf("%s criado.\n",FILENAME_DIR);
- printBytes("Tamanho",byteSize);
- //índice
- printf("\nCriando arquivo %s...\n",FILENAME_INDEX);
- FILE *file_index=fopen(FILENAME_INDEX,"wb+");
- fillFile(file_index,indexByteSize()*4,0);
- byteSize=getFileSize(file_index);
- fclose(file_index);
- printf("%s criado.\n",FILENAME_INDEX);
- printBytes("Tamanho",byteSize);
- //mestre
- printf("\nCriando arquivo %s...\n",FILENAME_MASTER);
- FILE *file_master=fopen(FILENAME_MASTER,"wb+");
- //fillFile(file_master,masterByteSize()*4,0);
- byteSize=getFileSize(file_master);
- fclose(file_master);
- printf("%s criado.\n",FILENAME_MASTER);
- printBytes("Tamanho",byteSize);
- }
- void printDirectory(Directory dir){
- int n=pow(2,dir.globalDepth);
- printf("Diretorio\n");
- printf("DIRECTORY(%i): [",n);
- for(int i=0;i<n;i++){
- printf("%i,",dir.directory[i]);
- }
- printf("]\n");
- printf("\n");
- }
- void printIndexes(){
- FILE *file_index=fopen(FILENAME_INDEX,FOPEN_MODE);
- int n=getFileSize(file_index)/indexByteSize();
- Index ind;
- printf("INDICE\n");
- for(int i=0;i<n;i++){
- ind=loadIndex(i);
- printf("INDEX [%i]:\n\tP': %i\n\tBUCKETS: \n",i,ind.localDepth);
- for(int j=0;j<BUCKETS_PER_PAGE;j++){
- printf("\t\t[%i]: CPF: %i, MASTER_INDEX: %i\n",j,ind.buckets[j].cpf,ind.buckets[j].masterIndex);
- }
- //printf("\t\t]\n");
- printf("\n");
- }
- fclose(file_index);
- printf("\n");
- }
- void printMaster(){
- FILE *file_master=fopen(FILENAME_MASTER,FOPEN_MODE);
- int n=getFileSize(file_master)/masterByteSize();
- Register data;
- printf("Mestre\n");
- for(int i=0;i<n;i++){
- data=loadMaster(i);
- printf("MASTER [%i]:\n\tCPF: %i\n\tName: %s\n\tDate: %s\n\tSex: %s\n",i,data.cpf,data.name,data.date,data.sex);
- }
- printf("\n");
- }
- void splitIndex(Index *ind, Directory *dir, int hash, Bucket b){//divide o índice em 2 e retorna o novo índice
- printf("\n[split index]");
- //printf("\ndir.globalDepth(%i),ind.localDepth(%i)",(*dir).globalDepth,(*ind).localDepth);
- if((*dir).globalDepth==(*ind).localDepth){//se a profundidade global e local forem iguais
- doubleDirectory(dir);//dobra o diretorio de tamanho
- }
- (*ind).localDepth++;
- for(int i=0;i<BUCKETS_PER_PAGE;i++){
- if((*ind).buckets[i].cpf>0){//se o valor do cpf for maior do que 0, ou seja, se o bucket não estiver vazio
- int rehash=hash_function((*ind).buckets[i].cpf,(*dir).globalDepth);//recalcula a hash do registro já inserido, baseado no p local
- //printf("\noldHash: %i,newHash: %i, CPFval[%i]:%i\n",hash,newHash,i,(*ind).buckets[i].cpf);
- //printf("\n\tREHASH ([%i]%i mod %i) directory[%i]=%i (newindex %i)",i,(*ind).buckets[i].cpf,intpow(2,(*ind).localDepth),newHash,(*dir).directory[newHash],new_index_index);
- //if((*dir).directory[newHash]==new_index_index){//se a nova hash retonar o valor correspondente á posição do índice novo no diretório
- if(hash!=rehash){
- Index rehashIndex;
- int rehash_index_index;
- if((*dir).directory[hash]==(*dir).directory[rehash]){
- rehash_index_index=increaseIndex();
- (*dir).directory[rehash]=rehash_index_index;
- rehashIndex=loadIndex(rehash_index_index);
- rehashIndex.localDepth=(*ind).localDepth;
- }else{
- rehash_index_index=(*dir).directory[rehash];
- rehashIndex=loadIndex(rehash_index_index);
- }
- int emptyBucket=getEmptyBucketPosition(rehashIndex);//busca o primeiro espaço vazio do novo índice
- if(emptyBucket>=0){
- rehashIndex.buckets[emptyBucket]=(*ind).buckets[i];//coloca o bucket nesse espaço
- (*ind).buckets[i].cpf=0;//"esvazia" o bucket no indice antigo
- }
- saveIndex(rehashIndex,rehash_index_index);
- }else if(b.cpf<(*ind).buckets[i].cpf){
- Bucket temp=(*ind).buckets[i];
- (*ind).buckets[i]=b;
- b=temp;
- }
- }
- }
- //inserindo o novo bucket.
- int newHash=hash_function(b.cpf,(*dir).globalDepth);//busca a posição diretório
- int new_index_index;
- Index newIndex;
- if(hash!=newHash){
- if((*dir).directory[hash]==(*dir).directory[newHash]){
- new_index_index=increaseIndex();
- (*dir).directory[newHash]=new_index_index;
- newIndex=loadIndex(new_index_index);
- newIndex.localDepth=(*ind).localDepth;
- }else{
- new_index_index=(*dir).directory[newHash];
- newIndex=loadIndex(new_index_index);
- }
- int emptyBucket=getEmptyBucketPosition(newIndex);
- if(emptyBucket>=0){
- newIndex.buckets[emptyBucket]=b;
- }else{
- splitIndex(&newIndex,dir,newHash,b);
- }
- saveIndex(newIndex,new_index_index);
- }else{
- int emptyBucket=getEmptyBucketPosition((*ind));
- if(emptyBucket>=0){
- (*ind).buckets[emptyBucket]=b;
- }else{
- splitIndex(ind,dir,hash,b);
- }
- }
- }
- void Simulation(Directory dir, int i){
- Register data;
- //int RandomCPF = (rand() % 9999999999);
- data.cpf=i+1;
- FILE *file_master=fopen(FILENAME_MASTER,FOPEN_MODE);//abre o arquivo mestre para obter o tamanho dele
- int masterIndex=getFileSize(file_master)/masterByteSize();//a posição no arquivo mestre será o tamanho total do arquivo / quantidade de bytes por registro
- fclose(file_master);//fecha o arquivo mestre
- //cria um bucket com o cpf atual e a posição do registro no arquivo mestre.
- Bucket b;
- b.cpf = data.cpf;
- b.masterIndex = masterIndex;
- int hash=hash_function(b.cpf, dir.globalDepth);//a função hash retorna a posição do diretório onde se encontra a posição do índice onde deve ficar o bucket com o cpf do novo registro.
- int index_index=dir.directory[hash];//busca a posição do índice onde o bucket será inserido.
- printf("\nHash function result: %i\nValue in directory: %i\nMaster index: %i\n",hash,index_index,masterIndex);
- Index ind=loadIndex(index_index);//carrega o índice do arquivo
- int emptyBucket=getEmptyBucketPosition(ind);//busca a primeira posição vazia dos buckets do índice
- if(emptyBucket>=0){//se houver um bucket vazio no índice...
- ind.buckets[emptyBucket]=b;//colocar o bucket criado naquele espaço.
- printf("\nInserido!\n");
- }else{//senao, divide o índice.
- splitIndex(&ind,&dir,hash,b);
- }
- saveIndex(ind, index_index);//salva o índice no arquivo.
- saveDirectory(dir);//salva o diretório.
- saveMaster(data,masterIndex);//salva todos os dados inseridos no arquivo mestre.
- }
- int main(){
- //unsigned int p=INITIAL_DEPTH, p_, index_tam=pow(2,INITIAL_DEPTH);//p é o tamanho do diretório; p_ é o p';
- //int masterIndex=-1;//masterIndex é a posição no arquivo mestre;
- //int dir_index;
- Register data;
- //Index *indices=malloc(index_tam*sizeof(Index));
- //loadIndexes(indices, dir);
- Directory dir;
- loadDirectory(&dir);
- int op;
- printf("~Sistema de Cadastro de Prontuarios para uma Empresa de Planos de Saude~\n");
- while(true){
- printf("\n========[MENU]========\n");
- printf("[0]\tExit\n[1]\tCriar arquivos\n[2]\tInserir registro\n[3]\tEditar registro\n[4]\tRemover registro\n[5]\tImprimir arquivos\n[6]\tSimulacao\n\n");
- printf("Digite a opcao: ");
- scanf("%i",&op);
- printf("\n");
- switch(op){
- default:
- printf("Opcao invalida!!!\n");
- break;
- case 1: //Criar arquivos
- createFiles();
- loadDirectory(&dir);
- break;
- case 2: //Inserir registro
- printf("CPF do cliente: ");
- scanf("%d", &data.cpf);
- printf("Nome do cliente: ");
- scanf("%s", &data.name);
- printf("Data de nascimento: ");
- scanf("%s", &data.date);
- printf("Sexo (m ou f): ");
- scanf("%s", &data.sex);
- FILE *file_master=fopen(FILENAME_MASTER,FOPEN_MODE);//abre o arquivo mestre para obter o tamanho dele
- int masterIndex=getFileSize(file_master)/masterByteSize();//a posição no arquivo mestre será o tamanho total do arquivo / quantidade de bytes por registro
- fclose(file_master);//fecha o arquivo mestre
- //cria um bucket com o cpf atual e a posição do registro no arquivo mestre.
- Bucket b;
- b.cpf = data.cpf;
- b.masterIndex = masterIndex;
- int hash=hash_function(b.cpf, dir.globalDepth);//a função hash retorna a posição do diretório onde se encontra a posição do índice onde deve ficar o bucket com o cpf do novo registro.
- int index_index=dir.directory[hash];//busca a posição do índice onde o bucket será inserido.
- printf("\nHash function result: %i\nValue in directory: %i\nMaster index: %i\n",hash,index_index,masterIndex);
- Index ind=loadIndex(index_index);//carrega o índice do arquivo
- int emptyBucket=getEmptyBucketPosition(ind);//busca a primeira posição vazia dos buckets do índice
- if(emptyBucket>=0){//se houver um bucket vazio no índice...
- ind.buckets[emptyBucket]=b;//colocar o bucket criado naquele espaço.
- }else{//senao, divide o índice.
- splitIndex(&ind,&dir,hash,b);
- }
- saveIndex(ind, index_index);//salva o índice no arquivo.
- saveDirectory(dir);//salva o diretório.
- saveMaster(data,masterIndex);//salva todos os dados inseridos no arquivo mestre.
- break;
- case 3:
- printf("Qual registro deseja editar?\n");
- scanf("%i", &data.cpf);
- hash=hash_function(data.cpf, dir.globalDepth);//hash recebe o resultado da função hash
- index_index=dir.directory[hash];//index_index recebe o apontador presente na posição especificada pela hash
- ind=loadIndex(index_index);//carrega o indice da posicao especificada
- int bucketRegister=getRegisterPosition(data.cpf,ind);//procura o registro especificado no indice
- if(bucketRegister==-1){//se o retorno for -1 o registro não existe
- printf("Registro inexistente");
- break;
- }
- printf("Nome do cliente: ");
- scanf("%s", &data.name);
- printf("Data de nascimento: ");
- scanf("%s", &data.date);
- printf("Sexo (m ou f): ");
- scanf("%s", &data.sex);
- int pos_m=ind.buckets[bucketRegister].masterIndex;//pos_m recebe a posição do registro no arquivo master
- saveMaster(data,pos_m);//salva todos os dados inseridos no arquivo mestre.
- break;
- case 4://remover registro
- printf("Qual registro deseja excluir?\n");
- scanf("%i", &data.cpf);
- hash=hash_function(data.cpf, dir.globalDepth);//hash recebe o resultado da função hash
- index_index=dir.directory[hash];//index_index recebe o apontador presente na posição especificada pela hash
- ind=loadIndex(index_index);//carrega o indice da posicao especificada
- bucketRegister=getRegisterPosition(data.cpf,ind);//procura o registro especificado no indice
- if(bucketRegister==-1){//se o retorno for -1 o registro não existe
- printf("Registro inexistente");
- break;
- }
- b.cpf=0;
- ind.buckets[bucketRegister]=b;
- saveIndex(ind, index_index);//salva o índice no arquivo.
- break;
- case 5://imprimir arquivos
- printDirectory(dir);
- printIndexes();
- printMaster();
- break;
- case 6:
- for(int i=0; i<50; i++)
- Simulation(dir,i);
- break;
- }
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement