https://github.com/facebook/rocksdb
Raw File
Tip revision: 91c01485d1c0a4675e24b39ad2adb950a3a468e6 authored by Radheshyam Balasundaram on 29 July 2014, 00:14:25 UTC
Minor changes to CuckooTableBuilder
Tip revision: 91c0148
cuckoo_table_reader.cc
//  Copyright (c) 2014, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#ifndef ROCKSDB_LITE
#include "table/cuckoo_table_reader.h"

#include <string>
#include "table/meta_blocks.h"
#include "util/coding.h"

namespace rocksdb {

extern const uint64_t kCuckooTableMagicNumber;

CuckooTableReader::CuckooTableReader(
    const Options& options,
    std::unique_ptr<RandomAccessFile>&& file,
    uint64_t file_size,
    uint64_t (*GetSliceHashPtr)(const Slice&, uint32_t, uint64_t))
    : file_(std::move(file)),
      file_size_(file_size),
      GetSliceHash(GetSliceHashPtr) {
  if (!options.allow_mmap_reads) {
    status_ = Status::InvalidArgument("File is not mmaped");
  }
  TableProperties* props = nullptr;
  status_ = ReadTableProperties(file_.get(), file_size, kCuckooTableMagicNumber,
      options.env, options.info_log.get(), &props);
  if (!status_.ok()) {
    return;
  }
  table_props_.reset(props);
  auto& user_props = props->user_collected_properties;
  auto hash_funs = user_props.find(CuckooTablePropertyNames::kNumHashTable);
  if (hash_funs == user_props.end()) {
    status_ = Status::InvalidArgument("Number of hash functions not found");
    return;
  }
  num_hash_fun_ = *reinterpret_cast<const uint32_t*>(hash_funs->second.data());
  auto unused_key = user_props.find(CuckooTablePropertyNames::kEmptyKey);
  if (unused_key == user_props.end()) {
    status_ = Status::InvalidArgument("Empty bucket value not found");
    return;
  }
  unused_key_ = unused_key->second;

  key_length_ = props->fixed_key_len;
  auto value_length = user_props.find(CuckooTablePropertyNames::kValueLength);
  if (value_length == user_props.end()) {
    status_ = Status::InvalidArgument("Value length not found");
    return;
  }
  value_length_ = *reinterpret_cast<const uint32_t*>(
      value_length->second.data());
  bucket_length_ = key_length_ + value_length_;

  auto num_buckets = user_props.find(CuckooTablePropertyNames::kMaxNumBuckets);
  if (num_buckets == user_props.end()) {
    status_ = Status::InvalidArgument("Num buckets not found");
    return;
  }
  num_buckets_ = *reinterpret_cast<const uint64_t*>(num_buckets->second.data());
  auto is_last_level = user_props.find(CuckooTablePropertyNames::kIsLastLevel);
  if (is_last_level == user_props.end()) {
    status_ = Status::InvalidArgument("Is last level not found");
    return;
  }
  is_last_level_ = *reinterpret_cast<const bool*>(is_last_level->second.data());
  status_ = file_->Read(0, file_size, &file_data_, nullptr);
}

Status CuckooTableReader::Get(
    const ReadOptions& readOptions, const Slice& key, void* handle_context,
    bool (*result_handler)(void* arg, const ParsedInternalKey& k,
                           const Slice& v),
    void (*mark_key_may_exist_handler)(void* handle_context)) {
  ParsedInternalKey ikey;
  if (!ParseInternalKey(key, &ikey)) {
    return Status::Corruption("Unable to parse key into inernal key.");
  }
  for (uint32_t hash_cnt = 0; hash_cnt < num_hash_fun_; ++hash_cnt) {
    uint64_t hash_val = GetSliceHash(ikey.user_key, hash_cnt, num_buckets_);
    assert(hash_val < num_buckets_);
    uint64_t offset = hash_val * bucket_length_;
    const char* bucket = &file_data_.data()[offset];
    if (unused_key_.compare(0, key_length_, bucket, key_length_) == 0) {
      return Status::OK();
    }
    // Here, we compare only the user key part as we support only one entry
    // per user key and we don't support sanpshot.
    if (ikey.user_key.compare(Slice(bucket, ikey.user_key.size())) == 0) {
      Slice value = Slice(&bucket[key_length_], value_length_);
      result_handler(handle_context, ikey, value);
      // We don't support merge operations. So, we return here.
      return Status::OK();
    }
  }
  return Status::OK();
}

Iterator* CuckooTableReader::NewIterator(const ReadOptions&, Arena* arena) {
  // TODO(rbs): Implement this as this will be used in compaction.
  return nullptr;
}
}  // namespace rocksdb
#endif
back to top