struct tm *ol_sniff(ol_database *db, const char *key, size_t klen) { char _key[KEY_SIZE] = {'\0'}; size_t _klen = 0; ol_bucket *bucket = ol_get_bucket(db, key, klen, &_key, &_klen); check_warn(_klen > 0, "Key length of zero not allowed."); if (bucket != NULL && bucket->expiration != NULL) { if (!_has_bucket_expired(bucket)) { return bucket->expiration; } else { /* It's dead, get rid of it. */ check(ol_scoop(db, key, klen) == 0, "Could not delete a bucket!") } } error: return NULL; }
int ol_aol_restore(ol_database *db) { ol_string *command = NULL, *key = NULL, *value = NULL, *ct = NULL, *read_data_size = NULL, *read_org_size = NULL; FILE *fd = fopen(db->aol_file, "r"); check(fd, "Error opening file"); while (!feof(fd)) { command = _ol_read_data(fd); check(command, "Error reading"); /* Kind of a hack to check for EOF. If the struct is blank, then we * read past EOF in _ol_read_data. feof is rarely useful I guess... */ if (command->data == NULL) { free(command); break; } key = _ol_read_data(fd); check(key, "Error reading"); /* Everything needs a key */ if (strncmp(command->data, "JAR", 3) == 0) { ct = _ol_read_data(fd); check(ct, "Error reading"); read_org_size = _ol_read_data(fd); check(read_org_size, "Error reading"); read_data_size = _ol_read_data(fd); check(read_data_size, "Error reading"); value = _ol_read_data(fd); check(value, "Error reading"); size_t original_size = (size_t)strtol(read_org_size->data, NULL, 10); size_t compressed_size = (size_t)strtol(read_data_size->data, NULL, 10); size_t data_offset = (size_t)strtol(value->data, NULL, 10); /* Pointer in the values file to where the data for this command * should be. */ unsigned char *data_ptr = db->values + data_offset; /* Short circuit check to see if the memory in the location is all * null. */ int memory_is_not_null = 0; int i = 0; for (; i < compressed_size; i++) { if ('\0' != data_ptr[i]) { debug("Data is not null on %zu.", data_offset + i); memory_is_not_null = 1; break; } } if (memory_is_not_null) { /* Turns out that in rare cases LZ4 will compress to exactly * the same size as it's starting string. This means we can't * just check to see if original_size != compressed_size, so * instead we first attempt to decompress and check how many * chars were processed. */ char tmp_data[original_size]; char *ret = memset(&tmp_data, 0, original_size); check(ret == tmp_data, "Could not initialize tmp_data parameter."); int processed = LZ4_decompress_fast((const char*)data_ptr, (char *)tmp_data, original_size); if (processed == compressed_size) ol_jar_ct(db, key->data, key->dlen, (unsigned char*)tmp_data, original_size, ct->data, ct->dlen); else { if (original_size != compressed_size) ol_log_msg(LOG_WARN, "Could not decompress data that is probably compressed. Data may have been deleted."); /* Now that we've tried to decompress and failed, send off the raw data instead. */ ol_jar_ct(db, key->data, key->dlen, data_ptr, compressed_size, ct->data, ct->dlen); } } #ifdef DEBUG /* This happens a lot and isn't bad, so I'm commenting it out. */ else ol_log_msg(LOG_WARN, "No data in values file that corresponds with this key. Key has been deleted or updated."); #endif /* Important: Set the new offset to compressed_size + data_offset. * We need to do this because compaction/squishing will leave holes * in the data that we need to account for during replay. */ db->val_size = compressed_size + data_offset; ol_string_free(&read_org_size); ol_string_free(&read_data_size); ol_string_free(&ct); ol_string_free(&value); } else if (strncmp(command->data, "SCOOP", 5) == 0) ol_scoop(db, key->data, key->dlen); else if (strncmp(command->data, "SPOIL", 5) == 0) { ol_string *spoil = _ol_read_data(fd); check(spoil != NULL, "Could not read the rest of SPOIL command for AOL."); struct tm time = {0}; _deserialize_time(&time, spoil->data); check(spoil, "Error reading"); ol_spoil(db, key->data, key->dlen, &time); ol_string_free(&spoil); } /* Strip the newline char after each "record" */ char c; check(fread(&c, 1, 1, fd) != 0, "Error reading"); check(c == '\n', "Could not strip newline"); ol_string_free(&command); ol_string_free(&key); } fclose(fd); return 0; error: ol_log_msg(LOG_ERR, "Restore failed. Corrupt AOL?"); /* Free all the stuff */ ol_string_free(&command); ol_string_free(&key); ol_string_free(&value); ol_string_free(&ct); ol_string_free(&read_org_size); ol_string_free(&read_data_size); if (fd != NULL) fclose(fd); return -1; }