text: // Copyright (c) 2018 Benoit Chesneau
  //
  // This file is provided to you under the Apache License,
  // Version 2.0 (the "License"); you may not use this file
  // except in compliance with the License.  You may obtain
  // a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  //
  #include <array>
  #include <string>
  
  #include "rocksdb/cache.h"
  #include "rocksdb/write_buffer_manager.h"
  
  #include "atoms.h"
  #include "env.h"
  #include "cache.h"
  #include "write_buffer_manager.h"
  #include "util.h"
  
  namespace erocksdb {
  
  ErlNifResourceType * WriteBufferManager::m_WriteBufferManager_RESOURCE(NULL);
  
  void
  WriteBufferManager::CreateWriteBufferManagerType( ErlNifEnv * env)
  {
      ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER);
      m_WriteBufferManager_RESOURCE = enif_open_resource_type(env, NULL, "erocksdb_WriteBufferManager",
                                              &WriteBufferManager::WriteBufferManagerResourceCleanup,
                                              flags, NULL);
      return;
  }   // WriteBufferManager::CreateWriteBufferManagerType
  
  
  void
  WriteBufferManager::WriteBufferManagerResourceCleanup(ErlNifEnv * /*env*/, void * arg)
  {
      WriteBufferManager* mgr_ptr = (WriteBufferManager *)arg;
      mgr_ptr->~WriteBufferManager();
      mgr_ptr = nullptr;
      return;
  }   // WriteBufferManager::WriteBufferManagerResourceCleanup
  
  
  WriteBufferManager *
  WriteBufferManager::CreateWriteBufferManagerResource(std::shared_ptr<rocksdb::WriteBufferManager> mgr)
  {
      WriteBufferManager * ret_ptr;
      void * alloc_ptr;
  
      alloc_ptr=enif_alloc_resource(m_WriteBufferManager_RESOURCE, sizeof(WriteBufferManager));
      ret_ptr=new (alloc_ptr) WriteBufferManager(mgr);
      return(ret_ptr);
  }
  
  WriteBufferManager *
  WriteBufferManager::RetrieveWriteBufferManagerResource(ErlNifEnv * Env, const ERL_NIF_TERM & term)
  {
      WriteBufferManager * ret_ptr;
      if (!enif_get_resource(Env, term, m_WriteBufferManager_RESOURCE, (void **)&ret_ptr))
          return NULL;
      return ret_ptr;
  }
  
  WriteBufferManager::WriteBufferManager(std::shared_ptr<rocksdb::WriteBufferManager> Mgr) : mgr_(Mgr) {}
  
  WriteBufferManager::~WriteBufferManager()
  {
      if(mgr_)
      {
          mgr_ = nullptr;
      }
      return;
  }
  
  std::shared_ptr<rocksdb::WriteBufferManager> WriteBufferManager::write_buffer_manager() {
      auto m = mgr_;
      return m;
  }
  
  
  
  ERL_NIF_TERM
  NewWriteBufferManager(
          ErlNifEnv* env,
          int argc,
          const ERL_NIF_TERM argv[])
  {
  
      int buffer_size;
      if(!enif_get_int(env, argv[0], &buffer_size))
          return enif_make_badarg(env);
      std::shared_ptr<rocksdb::WriteBufferManager> sptr_write_buffer_manager;
      if(argc == 1) {
          sptr_write_buffer_manager = std::make_shared<rocksdb::WriteBufferManager>(buffer_size);
      } else {
          erocksdb::Cache* cache_ptr = erocksdb::Cache::RetrieveCacheResource(env,argv[1]);
          if(NULL==cache_ptr)
              return enif_make_badarg(env);
  
          sptr_write_buffer_manager = std::make_shared<rocksdb::WriteBufferManager>(buffer_size, cache_ptr->cache());
      }
      auto mgr_ptr = WriteBufferManager::CreateWriteBufferManagerResource(sptr_write_buffer_manager);
      // create a resource reference to send erlang
      ERL_NIF_TERM result = enif_make_resource(env, mgr_ptr);
      // clear the automatic reference from enif_alloc_resource in EnvObject
      enif_release_resource(mgr_ptr);
      sptr_write_buffer_manager.reset();
      sptr_write_buffer_manager = nullptr;
      return enif_make_tuple2(env, ATOM_OK, result);
  }
  
  ERL_NIF_TERM
  ReleaseWriteBufferManager(ErlNifEnv* env, int /*argc*/, const ERL_NIF_TERM argv[])
  {
      WriteBufferManager* mgr_ptr;
      std::shared_ptr<rocksdb::WriteBufferManager> mgr;
  
      mgr_ptr = erocksdb::WriteBufferManager::RetrieveWriteBufferManagerResource(env, argv[0]);
      if(nullptr==mgr_ptr)
          return ATOM_OK;
      mgr = mgr_ptr->write_buffer_manager();
      mgr.reset();
      mgr = nullptr;
      mgr_ptr = nullptr;
      return ATOM_OK;
  }
  
  ERL_NIF_TERM
  wbf_info(
          ErlNifEnv *env,
          WriteBufferManager* mgr_ptr,
          ERL_NIF_TERM item)
  {
      if (item == erocksdb::ATOM_MEMORY_USAGE) {
          return enif_make_uint64(env,mgr_ptr->write_buffer_manager()->memory_usage());
      } else if (item == erocksdb::ATOM_MUTABLE_MEMTABLE_MEMORY_USAGE) {
          return enif_make_uint64(env, mgr_ptr->write_buffer_manager()->mutable_memtable_memory_usage());
      } else if (item == erocksdb::ATOM_BUFFER_SIZE) {
          return enif_make_uint64(env, mgr_ptr->write_buffer_manager()->buffer_size());
      } else if (item == erocksdb::ATOM_ENABLED) {
          if(mgr_ptr->write_buffer_manager()->enabled())
              return ATOM_TRUE;
          return ATOM_FALSE;
  
      } else {
          return enif_make_badarg(env);
      }
  }
  
  
  ERL_NIF_TERM
  WriteBufferManagerInfo(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  {
      WriteBufferManager* mgr_ptr;
      mgr_ptr = erocksdb::WriteBufferManager::RetrieveWriteBufferManagerResource(env, argv[0]);
      if(nullptr == mgr_ptr)
          return enif_make_badarg(env);
  
      if (argc > 1)
      {
          return wbf_info(env, std::move(mgr_ptr), argv[1]);
      }
  
      std::array<ERL_NIF_TERM, 4> items = {
          erocksdb::ATOM_ENABLED,
          erocksdb::ATOM_BUFFER_SIZE,
          erocksdb::ATOM_MUTABLE_MEMTABLE_MEMORY_USAGE,
          erocksdb::ATOM_MEMORY_USAGE
      };
  
      ERL_NIF_TERM info = enif_make_list(env, 0);
      for(const auto& item : items) {
          info = enif_make_list_cell(
                  env,
                  enif_make_tuple2(env, item, wbf_info(env, mgr_ptr, item)),
                  info);
      }
  
      return info;
  }
  
  }
  