blob: bd9fe762e39c17776f1253504b69d681a92531ee [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_TABLET_MUTATION_H
#define KUDU_TABLET_MUTATION_H
#include <cstdint>
#include <cstring>
#include <new>
#include <ostream>
#include <string>
#include <glog/logging.h>
#include "kudu/common/row_changelist.h"
#include "kudu/common/timestamp.h"
#include "kudu/gutil/atomicops.h"
#include "kudu/gutil/macros.h"
#include "kudu/gutil/port.h"
#include "kudu/util/slice.h"
namespace kudu {
class Schema;
namespace tablet {
// A single mutation associated with a row.
// This object also acts as a node in a linked list connected to other
// mutations in the row.
//
// This is a variable-length object.
class Mutation {
public:
Mutation() { }
// Create a new Mutation object with a copy of the given changelist.
// The object is allocated from the provided Arena.
template<class ArenaType>
static Mutation *CreateInArena(
ArenaType *arena, Timestamp timestamp, const RowChangeList &rcl);
RowChangeList changelist() const {
return RowChangeList(Slice(changelist_data_, changelist_size_));
}
Timestamp timestamp() const { return timestamp_; }
Mutation *next() { return next_; }
const Mutation *next() const { return next_; }
// Same as 'next()' but loads with 'Acquire' ordering semantics.
// This must be used when traversing the mutation list associated with
// an in-memory store.
const Mutation* acquire_next() const {
return reinterpret_cast<const Mutation*>(base::subtle::Acquire_Load(
reinterpret_cast<const AtomicWord*>(&next_)));
}
Mutation* acquire_next() {
return reinterpret_cast<Mutation*>(base::subtle::Acquire_Load(
reinterpret_cast<AtomicWord*>(&next_)));
}
void set_next(Mutation *next) {
next_ = next;
}
// Return a stringified version of the given list of mutations.
// This should only be used for debugging/logging.
static std::string StringifyMutationList(const Schema &schema, const Mutation *head);
// Appends this mutation to the list given by 'redo_head' and 'redo_tail'.
//
// This function is atomic provided that callers are externally synchronized
// on a per mutation list (i.e. per row) basis. Without this synchronization,
// the non-atomicity between 'redo_head' and 'redo_tail' writes may cause errors.
//
// This operation uses "Release" memory semantics (see atomicops.h). The
// pointers as well as all of the mutations in the list must be word-aligned.
void AppendToListAtomic(Mutation** redo_head, Mutation** redo_tail);
void PrependToList(Mutation** list) {
this->next_ = *list;
*list = this;
}
// O(n) algorithm to reverse the order of a linked list of mutations.
static void ReverseMutationList(Mutation** list);
private:
friend class MSRow;
friend class MemRowSet;
// The op timestamp which made this mutation. If this op is not committed in
// the snapshot of the reader, this mutation should be ignored.
Timestamp timestamp_;
// Link to the next mutation on this row
Mutation *next_;
uint32_t changelist_size_;
// The actual encoded RowChangeList
char changelist_data_[0];
DISALLOW_COPY_AND_ASSIGN(Mutation);
};
template<class ArenaType>
inline Mutation *Mutation::CreateInArena(
ArenaType *arena, Timestamp timestamp, const RowChangeList &rcl) {
DCHECK(!rcl.is_null());
size_t size = sizeof(Mutation) + rcl.slice().size();
void *storage = arena->AllocateBytesAligned(size, BASE_PORT_H_ALIGN_OF(Mutation));
CHECK(storage) << "failed to allocate storage from arena";
auto ret = new (storage) Mutation();
ret->timestamp_ = timestamp;
ret->next_ = NULL;
ret->changelist_size_ = rcl.slice().size();
memcpy(ret->changelist_data_, rcl.slice().data(), rcl.slice().size());
return ret;
}
inline void Mutation::ReverseMutationList(Mutation** list) {
Mutation* prev = nullptr;
Mutation* cur = *list;
while (cur != nullptr) {
Mutation* next = cur->next_;
cur->next_ = prev;
prev = cur;
cur = next;
}
*list = prev;
}
} // namespace tablet
} // namespace kudu
#endif