<commit_before>// 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.

#include "db/table_cache.h"

#include "db/filename.h"
#include "db/log_reader.h"
#include "db/log_writer.h"
#include "db/version_edit.h"
#include "leveldb/env.h"
#include "leveldb/table.h"
#include "util/coding.h"
#include "leveldb/perf_count.h"

namespace leveldb {

static void DeleteEntry(const Slice& key, void* value) {
  TableAndFile* tf = reinterpret_cast<TableAndFile*>(value);
  if (0==dec_and_fetch(&tf->user_count))
  {
      if (NULL!=tf->doublecache)
          tf->doublecache->SubFileSize(tf->table->GetFileSize());
      delete tf->table;
      delete tf->file;
      delete tf;
  }   // if
}

static void UnrefEntry(void* arg1, void* arg2) {
  Cache* cache = reinterpret_cast<Cache*>(arg1);
  Cache::Handle* h = reinterpret_cast<Cache::Handle*>(arg2);
  cache->Release(h);
}

TableCache::TableCache(const std::string& dbname,
                       const Options* options,
                       Cache * file_cache,
                       DoubleCache & doublecache)
    : env_(options->env),
      dbname_(dbname),
      options_(options),
      cache_(file_cache),
      doublecache_(doublecache)
{
}

TableCache::~TableCache() {
}

Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, int level,
                             Cache::Handle** handle, bool is_compaction,
                             bool for_iterator) {
  Status s;
  char buf[sizeof(file_number)];
  EncodeFixed64(buf, file_number);
  Slice key(buf, sizeof(buf));
  *handle = cache_->Lookup(key);
  if (*handle == NULL) {
    std::string fname = TableFileName(*options_, file_number, level);
    RandomAccessFile* file = NULL;
    Table* table = NULL;
    s = env_->NewRandomAccessFile(fname, &file);
    if (s.ok()) {
      s = Table::Open(*options_, file, file_size, &table);

      // Riak:  support opportunity to manage Linux page cache
      if (is_compaction)
          file->SetForCompaction(file_size);
    }

    if (!s.ok()) {
      assert(table == NULL);
      delete file;
      // We do not cache error results so that if the error is transient,
      // or somebody repairs the file, we recover automatically.
    } else {
      TableAndFile* tf = new TableAndFile;
      tf->file = file;
      tf->table = table;
      tf->doublecache = &doublecache_;
      tf->file_number = file_number;
      tf->level = level;

      *handle = cache_->Insert(key, tf, table->TableObjectSize(), &DeleteEntry);
      gPerfCounters->Inc(ePerfTableOpened);
      doublecache_.AddFileSize(table->GetFileSize());

      // temporary hardcoding to match number of levels defined as
      //  overlapped in version_set.cc
      if (level<config::kNumOverlapLevels)
          cache_->Addref(*handle);
    }
  }
  else
  {
      Table *table = reinterpret_cast<TableAndFile*>(cache_->Value(*handle))->table;

      // this is NOT first access, see if bloom filter can load now
      if (!for_iterator && table->ReadFilter())
      {
          // TableAndFile now going to be present in two cache entries
          TableAndFile* tf = reinterpret_cast<TableAndFile*>(cache_->Value(*handle));
          inc_and_fetch(&tf->user_count);

          //  must clean file size, do not want double count
          if (NULL!=tf->doublecache)
              tf->doublecache->SubFileSize(tf->table->GetFileSize());

          cache_->Release(*handle);
          if (tf->level<config::kNumOverlapLevels)
              cache_->Release(*handle);

          *handle = cache_->Insert(key, tf, table->TableObjectSize(), &DeleteEntry);
          if (level<config::kNumOverlapLevels)
              cache_->Addref(*handle);

          gPerfCounters->Inc(ePerfDebug0);
      }   // if

      // for Linux, let fadvise start precaching
      if (is_compaction)
      {
          RandomAccessFile *file = reinterpret_cast<TableAndFile*>(cache_->Value(*handle))->file;
          file->SetForCompaction(file_size);
      }   // if

      gPerfCounters->Inc(ePerfTableCached);
  }   // else
  return s;
}

Iterator* TableCache::NewIterator(const ReadOptions& options,
                                  uint64_t file_number,<commit_msg>add comments for code review<commit_after>// 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.

#include "db/table_cache.h"

#include "db/filename.h"
#include "db/log_reader.h"
#include "db/log_writer.h"
#include "db/version_edit.h"
#include "leveldb/env.h"
#include "leveldb/table.h"
#include "util/coding.h"
#include "leveldb/perf_count.h"

namespace leveldb {

static void DeleteEntry(const Slice& key, void* value) {
  TableAndFile* tf = reinterpret_cast<TableAndFile*>(value);
  if (0==dec_and_fetch(&tf->user_count))
  {
      if (NULL!=tf->doublecache)
          tf->doublecache->SubFileSize(tf->table->GetFileSize());
      delete tf->table;
      delete tf->file;
      delete tf;
  }   // if
}

static void UnrefEntry(void* arg1, void* arg2) {
  Cache* cache = reinterpret_cast<Cache*>(arg1);
  Cache::Handle* h = reinterpret_cast<Cache::Handle*>(arg2);
  cache->Release(h);
}

TableCache::TableCache(const std::string& dbname,
                       const Options* options,
                       Cache * file_cache,
                       DoubleCache & doublecache)
    : env_(options->env),
      dbname_(dbname),
      options_(options),
      cache_(file_cache),
      doublecache_(doublecache)
{
}

TableCache::~TableCache() {
}

Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, int level,
                             Cache::Handle** handle, bool is_compaction,
                             bool for_iterator) {
  Status s;
  char buf[sizeof(file_number)];
  EncodeFixed64(buf, file_number);
  Slice key(buf, sizeof(buf));
  *handle = cache_->Lookup(key);
  if (*handle == NULL) {
    std::string fname = TableFileName(*options_, file_number, level);
    RandomAccessFile* file = NULL;
    Table* table = NULL;
    s = env_->NewRandomAccessFile(fname, &file);
    if (s.ok()) {
      s = Table::Open(*options_, file, file_size, &table);

      // Riak:  support opportunity to manage Linux page cache
      if (is_compaction)
          file->SetForCompaction(file_size);
    }

    if (!s.ok()) {
      assert(table == NULL);
      delete file;
      // We do not cache error results so that if the error is transient,
      // or somebody repairs the file, we recover automatically.
    } else {
      TableAndFile* tf = new TableAndFile;
      tf->file = file;
      tf->table = table;
      tf->doublecache = &doublecache_;
      tf->file_number = file_number;
      tf->level = level;

      *handle = cache_->Insert(key, tf, table->TableObjectSize(), &DeleteEntry);
      gPerfCounters->Inc(ePerfTableOpened);
      doublecache_.AddFileSize(table->GetFileSize());

      // temporary hardcoding to match number of levels defined as
      //  overlapped in version_set.cc
      if (level<config::kNumOverlapLevels)
          cache_->Addref(*handle);
    }
  }
  else
  {
      Table *table = reinterpret_cast<TableAndFile*>(cache_->Value(*handle))->table;

      // this is NOT first access, see if bloom filter can load now
      if (!for_iterator && table->ReadFilter())
      {
          // TableAndFile now going to be present in two cache entries
	  //  1. retrieve old entry within file cache
          TableAndFile* tf = reinterpret_cast<TableAndFile*>(cache_->Value(*handle));
          inc_and_fetch(&tf->user_count);

          //  2. must clean file size, do not want double count
          if (NULL!=tf->doublecache)
              tf->doublecache->SubFileSize(tf->table->GetFileSize());

	  //  3. release current reference (and possible special overlap reference)
          cache_->Release(*handle);
          if (tf->level<config::kNumOverlapLevels)
              cache_->Release(*handle);

	  //  4. create second table cache entry using TableObjectSize that now includes
	  //     bloom filter size
          *handle = cache_->Insert(key, tf, table->TableObjectSize(), &DeleteEntry);

	  //  5. set double reference if an overlapped file (prevents from being flushed)
          if (level<config::kNumOverlapLevels)
              cache_->Addref(*handle);

          gPerfCounters->Inc(ePerfDebug0);
      }   // if

      // for Linux, let fadvise start precaching
      if (is_compaction)
      {
          RandomAccessFile *file = reinterpret_cast<TableAndFile*>(cache_->Value(*handle))->file;
          file->SetForCompaction(file_size);
      }   // if

      gPerfCounters->Inc(ePerfTableCached);
  }   // else
  return s;
}

Iterator* TableCache::NewIterator(const ReadOptions& options,
                                  uint64_t file_number,
{'fraction_non_alphanumeric': 0.12297267273939125, 'fraction_numerical': 0.0045545434347922685, 'mean_word_length': 2.714108910891089, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 103, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '759980', 'n_tokens_mistral': 2741, 'n_tokens_neox': 2662, 'n_words': 672}