blob: b88d844c425785c6519e2b856834c01e53273990 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// 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.
#ifndef KUDU_CFILE_BLOCK_HANDLE_H
#define KUDU_CFILE_BLOCK_HANDLE_H
#include <memory>
#include <boost/variant/get.hpp>
#include <boost/variant/variant.hpp>
#include "kudu/cfile/block_cache.h"
#include "kudu/common/rowblock_memory.h"
#include "kudu/gutil/ref_counted.h"
namespace kudu {
namespace cfile {
// When blocks are read, they are sometimes resident in the block cache, and sometimes skip the
// block cache. In the case that they came from the cache, we just need to dereference them when
// they stop being used. In the case that they didn't come from cache, we need to actually free
// the underlying data.
//
// NOTE ON REFERENCE COUNTING
// ---------------------------
// Note that the BlockHandle itself may refer to a BlockCacheHandle, which itself is
// reference-counted. When all of the references to a BlockHandle go out of scope, it
// results in decrementing the BlockCacheHandle's reference count.
class BlockHandle final : public RefCountedThreadSafe<BlockHandle> {
public:
static scoped_refptr<BlockHandle> WithOwnedData(const Slice& data) {
return { new BlockHandle(data) };
}
static scoped_refptr<BlockHandle> WithDataFromCache(BlockCacheHandle handle) {
return { new BlockHandle(std::move(handle)) };
}
Slice data() const { return data_; }
scoped_refptr<BlockHandle> SubrangeBlock(size_t offset, size_t len) {
return { new BlockHandle(this, offset, len) };
}
protected:
friend class RefCountedThreadSafe<BlockHandle>;
// Marker to indicate that this object isn't initialized (owns no data).
struct Uninitialized {};
// Marker that the handle directly owns the data in 'data_', rather than referring
// to data in the block cache or to another BlockHandle.
struct OwnedData {};
~BlockHandle() {
Reset();
}
// Constructor for owned data.
explicit BlockHandle(Slice data)
: data_(data),
ref_(OwnedData{}) {
}
explicit BlockHandle(BlockCacheHandle dblk_data)
: data_(dblk_data.data()),
ref_(std::move(dblk_data)) {
}
BlockHandle(scoped_refptr<BlockHandle> other, size_t offset, size_t len)
: data_(other->data()),
ref_(std::move(other)) {
data_.remove_prefix(offset);
data_.truncate(len);
}
void Reset() {
if (boost::get<OwnedData>(&ref_) != nullptr) {
delete [] data_.data();
}
data_ = "";
ref_ = Uninitialized{};
}
Slice data_;
boost::variant<Uninitialized, OwnedData, BlockCacheHandle, scoped_refptr<BlockHandle>> ref_;
DISALLOW_COPY_AND_ASSIGN(BlockHandle);
};
} // namespace cfile
} // namespace kudu
#endif