blob: c470c2c2cb7acc20ebab5dbe6089d90850b18a60 [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.
*/
/*
* PdxType.cpp
*
* Created on: Nov 3, 2011
* Author: npatel
*/
#include "PdxType.hpp"
#include "PdxFieldType.hpp"
#include "PdxHelper.hpp"
#include "PdxTypeRegistry.hpp"
#include "Utils.hpp"
namespace apache {
namespace geode {
namespace client {
const char* PdxType::m_javaPdxClass = "org.apache.geode.pdx.internal.PdxType";
PdxType::~PdxType() noexcept {
_GEODE_SAFE_DELETE(m_pdxFieldTypes);
_GEODE_SAFE_DELETE_ARRAY(m_remoteToLocalFieldMap);
_GEODE_SAFE_DELETE_ARRAY(m_localToRemoteFieldMap);
}
PdxType::PdxType(PdxTypeRegistry& pdxTypeRegistry,
const std::string& pdxDomainClassName, bool isLocal)
: Serializable(),
m_pdxFieldTypes(new std::vector<std::shared_ptr<PdxFieldType>>()),
m_className(pdxDomainClassName),
m_geodeTypeId(0),
m_isLocal(isLocal),
m_numberOfVarLenFields(0),
m_varLenFieldIdx(0),
m_numberOfFieldsExtra(0),
m_isVarLenFieldAdded(false),
m_remoteToLocalFieldMap(nullptr),
m_localToRemoteFieldMap(nullptr),
m_noJavaClass(false),
m_pdxTypeRegistry(pdxTypeRegistry) {}
void PdxType::toData(DataOutput& output) const {
output.write(static_cast<int8_t>(DSCode::DataSerializable)); // 45
output.write(static_cast<int8_t>(DSCode::Class)); // 43
output.writeString(m_javaPdxClass);
// m_className
output.writeString(m_className);
// m_noJavaClass
output.writeBoolean(m_noJavaClass);
// m_geodeTypeId
output.writeInt(m_geodeTypeId);
// m_varLenFieldIdx
output.writeInt(m_varLenFieldIdx);
output.writeArrayLen(static_cast<int32_t>(m_pdxFieldTypes->size()));
for (std::vector<std::shared_ptr<PdxFieldType>>::iterator it =
m_pdxFieldTypes->begin();
it != m_pdxFieldTypes->end(); ++it) {
auto pdxPtr = *it;
pdxPtr->toData(output);
}
}
void PdxType::fromData(DataInput& input) {
input.read(); // ignore dsByte
input.read(); // ignore classByte
input.readString(); // ignore classtypeId
m_className = input.readString();
m_noJavaClass = input.readBoolean();
m_geodeTypeId = input.readInt32();
m_varLenFieldIdx = input.readInt32();
int len = input.readArrayLength();
bool foundVarLenType = false;
for (int i = 0; i < len; i++) {
auto pft = std::make_shared<PdxFieldType>();
pft->fromData(input);
m_pdxFieldTypes->push_back(pft);
if (pft->IsVariableLengthType() == true) foundVarLenType = true;
}
// as m_varLenFieldIdx starts with 0
if (m_varLenFieldIdx != 0) {
m_numberOfVarLenFields = m_varLenFieldIdx + 1;
} else if (foundVarLenType) {
m_numberOfVarLenFields = 1;
}
InitializeType();
}
void PdxType::addFixedLengthTypeField(const std::string& fieldName,
const std::string& className,
PdxFieldTypes typeId, int32_t size) {
if (m_fieldNameVsPdxType.find(fieldName) != m_fieldNameVsPdxType.end()) {
throw IllegalStateException("Field: " + fieldName +
" is already added to PdxWriter");
}
auto pfxPtr = std::make_shared<PdxFieldType>(
fieldName, className, typeId,
static_cast<int32_t>(m_pdxFieldTypes->size()), false, size, 0);
m_pdxFieldTypes->push_back(pfxPtr);
m_fieldNameVsPdxType[fieldName] = pfxPtr;
}
void PdxType::addVariableLengthTypeField(const std::string& fieldName,
const std::string& className,
PdxFieldTypes typeId) {
if (m_fieldNameVsPdxType.find(fieldName) != m_fieldNameVsPdxType.end()) {
throw IllegalStateException("Field: " + fieldName +
" is already added to PdxWriter");
}
if (m_isVarLenFieldAdded) {
m_varLenFieldIdx++; // it initial value is zero so variable length field
// idx start with zero
}
m_numberOfVarLenFields++;
m_isVarLenFieldAdded = true;
auto pfxPtr = std::make_shared<PdxFieldType>(
fieldName, className, typeId,
static_cast<int32_t>(m_pdxFieldTypes->size()), true, -1,
m_varLenFieldIdx);
m_pdxFieldTypes->push_back(pfxPtr);
m_fieldNameVsPdxType[fieldName] = pfxPtr;
}
void PdxType::initRemoteToLocal() {
// This method is to check if we have some extra fields in remote PdxType that
// are absent in local PdxType.
// 1. Get local PdxType from type registry
// 2. Get list of PdxFieldTypes from it
// 3. Use m_pdxFieldTypes for remote PdxType, that is populated in fromData
// 4. Iterate over local and remote PdxFieldTypes to compare individual type
// 5. If found update in m_remoteToLocalFieldMap that field there in remote
// type. else update m_numberOfFieldsExtra
// 6. else update in m_remoteToLocalFieldMap that local type don't have this
// fields
// 7. 1 = field there in remote type
// -1 = local type don't have this VariableLengthType field
// -2 = local type don't have this FixedLengthType field
std::shared_ptr<PdxType> localPdxType = nullptr;
//[TODO - open this up once PdxTypeRegistry is done]
localPdxType = m_pdxTypeRegistry.getLocalPdxType(m_className);
m_numberOfFieldsExtra = 0;
if (localPdxType != nullptr) {
std::vector<std::shared_ptr<PdxFieldType>>* localPdxFields =
localPdxType->getPdxFieldTypes();
int32_t fieldIdx = 0;
m_remoteToLocalFieldMap = new int32_t[m_pdxFieldTypes->size()];
LOGDEBUG(
"PdxType::initRemoteToLocal m_pdxFieldTypes->size() =%zu AND "
"localPdxFields->size()=%zu",
m_pdxFieldTypes->size(), localPdxFields->size());
for (std::vector<std::shared_ptr<PdxFieldType>>::iterator remotePdxField =
m_pdxFieldTypes->begin();
remotePdxField != m_pdxFieldTypes->end(); ++remotePdxField) {
bool found = false;
for (std::vector<std::shared_ptr<PdxFieldType>>::iterator localPdxfield =
localPdxFields->begin();
localPdxfield != localPdxFields->end(); ++localPdxfield) {
// PdxFieldType* remotePdx = (*(remotePdxField)).get();
// PdxFieldType* localPdx = (*(localPdxfield)).get();
if ((*localPdxfield)->equals(*remotePdxField)) {
found = true;
m_remoteToLocalFieldMap[fieldIdx++] = 1; // field there in remote
// type
break;
}
}
if (!found) {
// while writing take this from weakhashmap
// local field is not in remote type
// if((*(remotePdxField)).get()->IsVariableLengthType()) {
if ((*remotePdxField)->IsVariableLengthType()) {
m_remoteToLocalFieldMap[fieldIdx++] =
-1; // local type don't have this fields
} else {
m_remoteToLocalFieldMap[fieldIdx++] =
-2; // local type don't have this fields
}
m_numberOfFieldsExtra++;
}
}
}
}
void PdxType::initLocalToRemote() {
// This method is to check if we have some extra fields in remote PdxType that
// are absent in local PdxType.
// 1. Get local PdxType from type registry
// 2. Get list of PdxFieldTypes from it
// 3. Iterate over local PdxFields to compare it with remote PdxFields and if
// they r equal that means there sequence is same mark it with -2
// 4. Iterate over local PdxFields and remote PdxFields and if they are equal
// then mark m_localToRemoteFieldMap with remotePdxField sequenceId
// 5. else if local field is not in remote type then -1
std::shared_ptr<PdxType> localPdxType = nullptr;
localPdxType = m_pdxTypeRegistry.getLocalPdxType(m_className);
if (localPdxType != nullptr) {
std::vector<std::shared_ptr<PdxFieldType>>* localPdxFields =
localPdxType->getPdxFieldTypes();
int32_t fieldIdx = 0;
// type which need to read/write should control local type
int32_t localToRemoteFieldMapSize =
static_cast<int32_t>(localPdxType->m_pdxFieldTypes->size());
m_localToRemoteFieldMap = new int32_t[localToRemoteFieldMapSize];
for (int32_t i = 0; i < localToRemoteFieldMapSize &&
i < static_cast<int32_t>(m_pdxFieldTypes->size());
i++) {
// PdxFieldType* localPdx = localPdxFields->at(fieldIdx).get();
// PdxFieldType* remotePdx = m_pdxFieldTypes->at(i).get();
if (localPdxFields->at(fieldIdx)->equals(m_pdxFieldTypes->at(i))) {
// fields are in same order, we can read as it is
m_localToRemoteFieldMap[fieldIdx++] = -2;
} else {
break;
}
}
for (; fieldIdx < localToRemoteFieldMapSize;) {
auto localPdxField = localPdxType->m_pdxFieldTypes->at(fieldIdx);
bool found = false;
for (std::vector<std::shared_ptr<PdxFieldType>>::iterator remotePdxfield =
m_pdxFieldTypes->begin();
remotePdxfield != m_pdxFieldTypes->end(); ++remotePdxfield)
// for each(PdxFieldType^ remotePdxfield in m_pdxFieldTypes)
{
// PdxFieldType* localPdx = localPdxField.get();
PdxFieldType* remotePdx = (*(remotePdxfield)).get();
if (localPdxField->equals(*remotePdxfield)) {
found = true;
// store pdxfield type position to get the offset quickly
m_localToRemoteFieldMap[fieldIdx++] = remotePdx->getSequenceId();
break;
}
}
if (!found) {
// local field is not in remote type
m_localToRemoteFieldMap[fieldIdx++] = -1;
}
}
}
}
void PdxType::InitializeType() {
initRemoteToLocal(); // for writing
initLocalToRemote(); // for reading
generatePositionMap();
}
int32_t PdxType::getFieldPosition(const std::string& fieldName,
uint8_t* offsetPosition, int32_t offsetSize,
int32_t pdxStreamlen) {
auto pft = this->getPdxField(fieldName);
if (pft != nullptr) {
if (pft->IsVariableLengthType()) {
return variableLengthFieldPosition(pft, offsetPosition, offsetSize);
} else {
return fixedLengthFieldPosition(pft, offsetPosition, offsetSize,
pdxStreamlen);
}
}
return -1;
}
int32_t PdxType::getFieldPosition(int32_t fieldIdx, uint8_t* offsetPosition,
int32_t offsetSize, int32_t pdxStreamlen) {
auto pft = m_pdxFieldTypes->at(fieldIdx);
if (pft != nullptr) {
if (pft->IsVariableLengthType()) {
return variableLengthFieldPosition(pft, offsetPosition, offsetSize);
} else {
return fixedLengthFieldPosition(pft, offsetPosition, offsetSize,
pdxStreamlen);
}
}
return -1;
}
int32_t PdxType::fixedLengthFieldPosition(
std::shared_ptr<PdxFieldType> fixLenField, uint8_t* offsetPosition,
int32_t offsetSize, int32_t pdxStreamlen) {
int32_t offset = fixLenField->getVarLenOffsetIndex();
if (fixLenField->getRelativeOffset() >= 0) {
// starting fields
return fixLenField->getRelativeOffset();
} else if (offset == -1) // Pdx length
{
// there is no var len field so just subtracts relative offset from behind
return pdxStreamlen + fixLenField->getRelativeOffset();
} else {
// need to read offset and then subtract relative offset
// TODO
return PdxHelper::readInt(
offsetPosition +
(m_numberOfVarLenFields - offset - 1) * offsetSize,
offsetSize) +
fixLenField->getRelativeOffset();
}
}
int32_t PdxType::variableLengthFieldPosition(
std::shared_ptr<PdxFieldType> varLenField, uint8_t* offsetPosition,
int32_t offsetSize) {
int32_t offset = varLenField->getVarLenOffsetIndex();
if (offset == -1) {
return /*first var len field*/ varLenField->getRelativeOffset();
} else {
// we write offset from behind
return PdxHelper::readInt(
offsetPosition + (m_numberOfVarLenFields - offset - 1) * offsetSize,
offsetSize);
}
}
int32_t* PdxType::getLocalToRemoteMap() {
if (m_localToRemoteFieldMap != nullptr) {
return m_localToRemoteFieldMap;
}
ReadGuard guard(m_lockObj);
if (m_localToRemoteFieldMap != nullptr) {
return m_localToRemoteFieldMap;
}
initLocalToRemote();
return m_localToRemoteFieldMap;
}
int32_t* PdxType::getRemoteToLocalMap() {
if (m_remoteToLocalFieldMap != nullptr) {
return m_remoteToLocalFieldMap;
}
ReadGuard guard(m_lockObj);
if (m_remoteToLocalFieldMap != nullptr) {
return m_remoteToLocalFieldMap;
}
initRemoteToLocal();
return m_remoteToLocalFieldMap;
}
std::shared_ptr<PdxType> PdxType::isContains(std::shared_ptr<PdxType> first,
std::shared_ptr<PdxType> second) {
int j = 0;
for (int i = 0; i < static_cast<int>(second->m_pdxFieldTypes->size()); i++) {
auto secondPdt = second->m_pdxFieldTypes->at(i);
bool matched = false;
for (; j < static_cast<int>(first->m_pdxFieldTypes->size()); j++) {
auto firstPdt = first->m_pdxFieldTypes->at(j);
// PdxFieldType* firstType = firstPdt.get();
// PdxFieldType* secondType = secondPdt.get();
if (firstPdt->equals(secondPdt)) {
matched = true;
break;
}
}
if (!matched) return nullptr;
}
return first;
}
std::shared_ptr<PdxType> PdxType::clone() {
auto clone = std::make_shared<PdxType>(m_pdxTypeRegistry, m_className, false);
clone->m_geodeTypeId = 0;
clone->m_numberOfVarLenFields = m_numberOfVarLenFields;
for (std::vector<std::shared_ptr<PdxFieldType>>::iterator it =
m_pdxFieldTypes->begin();
it != m_pdxFieldTypes->end(); ++it) {
auto pdxPtr = *it;
clone->m_pdxFieldTypes->push_back(pdxPtr);
}
return clone;
}
std::shared_ptr<PdxType> PdxType::isLocalTypeContains(
std::shared_ptr<PdxType> otherType) {
if (m_pdxFieldTypes->size() >= otherType->m_pdxFieldTypes->size()) {
return isContains(shared_from_this(), otherType);
}
return nullptr;
}
std::shared_ptr<PdxType> PdxType::isRemoteTypeContains(
std::shared_ptr<PdxType> remoteType) {
if (m_pdxFieldTypes->size() <= remoteType->m_pdxFieldTypes->size()) {
return isContains(remoteType, shared_from_this());
}
return nullptr;
}
std::shared_ptr<PdxType> PdxType::mergeVersion(
std::shared_ptr<PdxType> otherVersion) {
// int nTotalFields = otherVersion->m_pdxFieldTypes->size();
std::shared_ptr<PdxType> contains = nullptr;
if (isLocalTypeContains(otherVersion) != nullptr) return shared_from_this();
if (isRemoteTypeContains(otherVersion) != nullptr) return otherVersion;
// need to create new one, clone of local
auto newone = clone();
int varLenFields = newone->getNumberOfVarLenFields();
for (std::vector<std::shared_ptr<PdxFieldType>>::iterator it =
otherVersion->m_pdxFieldTypes->begin();
it != otherVersion->m_pdxFieldTypes->end(); ++it) {
bool found = false;
// for each(PdxFieldType^ tmpNew in newone->m_pdxFieldTypes)
for (std::vector<std::shared_ptr<PdxFieldType>>::iterator it2 =
newone->m_pdxFieldTypes->begin();
it2 != newone->m_pdxFieldTypes->end(); ++it2) {
if ((*it2)->equals(*it)) {
found = true;
break;
}
}
if (!found) {
auto newFt = std::make_shared<PdxFieldType>(
(*it)->getFieldName(), (*it)->getClassName(), (*it)->getTypeId(),
static_cast<int32_t>(newone->m_pdxFieldTypes->size()), // sequence id
(*it)->IsVariableLengthType(), (*it)->getFixedSize(),
((*it)->IsVariableLengthType()
? varLenFields++ /*it increase after that*/
: 0));
newone->m_pdxFieldTypes->push_back(
newFt); // fieldnameVsPFT will happen after that
}
}
newone->setNumberOfVarLenFields(varLenFields);
if (varLenFields > 0) newone->setVarLenFieldIdx(varLenFields);
// need to keep all versions in local version
// m_otherVersions->Add(newone);
return newone;
}
void PdxType::generatePositionMap() {
bool foundVarLen = false;
int lastVarLenSeqId = 0;
int prevFixedSizeOffsets = 0;
// set offsets from back first
std::shared_ptr<PdxFieldType> previousField = nullptr;
for (int i = static_cast<int>(m_pdxFieldTypes->size()) - 1; i >= 0; i--) {
auto tmpft = m_pdxFieldTypes->at(i);
std::string temp = tmpft->getFieldName();
std::pair<std::string, std::shared_ptr<PdxFieldType>> pc(temp, tmpft);
m_fieldNameVsPdxType.insert(pc);
if (tmpft->IsVariableLengthType()) {
tmpft->setVarLenOffsetIndex(tmpft->getVarLenFieldIdx());
tmpft->setRelativeOffset(0);
foundVarLen = true;
lastVarLenSeqId = tmpft->getVarLenFieldIdx();
} else {
if (foundVarLen) {
tmpft->setVarLenOffsetIndex(lastVarLenSeqId);
// relative offset is subtracted from var len offsets
tmpft->setRelativeOffset(-tmpft->getFixedSize() +
previousField->getRelativeOffset());
} else {
tmpft->setVarLenOffsetIndex(-1); // Pdx header length
// relative offset is subtracted from var len offsets
tmpft->setRelativeOffset(-tmpft->getFixedSize());
if (previousField != nullptr) { // boundary condition
tmpft->setRelativeOffset(-tmpft->getFixedSize() +
previousField->getRelativeOffset());
}
}
}
previousField = tmpft;
}
foundVarLen = false;
prevFixedSizeOffsets = 0;
// now do optimization till you don't fine var len
for (uint32_t i = 0; (i < m_pdxFieldTypes->size()) && !foundVarLen; i++) {
auto tmpft = m_pdxFieldTypes->at(i);
if (tmpft->IsVariableLengthType()) {
tmpft->setVarLenOffsetIndex(-1); // first var len field
tmpft->setRelativeOffset(prevFixedSizeOffsets);
foundVarLen = true;
} else {
tmpft->setVarLenOffsetIndex(0); // no need to read offset
tmpft->setRelativeOffset(prevFixedSizeOffsets);
prevFixedSizeOffsets += tmpft->getFixedSize();
}
}
}
bool PdxType::Equals(std::shared_ptr<PdxType> otherObj) {
if (otherObj == nullptr) return false;
PdxType* ot = dynamic_cast<PdxType*>(otherObj.get());
if (ot == nullptr) return false;
if (ot == this) return true;
if (ot->m_pdxFieldTypes->size() != m_pdxFieldTypes->size()) return false;
for (uint32_t i = 0; i < m_pdxFieldTypes->size(); i++) {
if (!ot->m_pdxFieldTypes->at(i)->equals(m_pdxFieldTypes->at(i))) {
return false;
}
}
return true;
}
bool PdxType::operator<(const PdxType& other) const {
return this->m_className < other.m_className;
}
} // namespace client
} // namespace geode
} // namespace apache