blob: bf17ee3f55911d9a16237e8f91a75c95676d4b2f [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.
*/
#include "PdxType.hpp"
#include "PdxHelper.hpp"
#include "PdxTypeRegistry.hpp"
#include "../Log.hpp"
#include <msclr/lock.h>
#include "PdxWrapper.hpp"
#include "../Cache.hpp"
using namespace System;
namespace Apache
{
namespace Geode
{
namespace Client
{
namespace Internal
{
void PdxType::AddFixedLengthTypeField(String^ fieldName, String^ className,
PdxFieldTypes typeId, Int32 size)
{
int current = m_pdxFieldTypes->Count;
PdxFieldType^ pfType = gcnew PdxFieldType(fieldName, className, (Byte)typeId,
current/*field index*/,
false, size, 0/*var len field idx*/);
m_pdxFieldTypes->Add(pfType);
//this will make sure one can't add same field name
m_fieldNameVsPdxType->Add(fieldName, pfType);
}
void PdxType::AddVariableLengthTypeField(String^ fieldName, String^ className,
PdxFieldTypes typeId)
{
//we don't store offset of first var len field, this is the purpose of following check
if (m_isVarLenFieldAdded)
m_varLenFieldIdx++;//it initial value is zero so variable length field idx start with zero
m_numberOfVarLenFields++;
m_isVarLenFieldAdded = true;
int current = m_pdxFieldTypes->Count;
PdxFieldType^ pfType = gcnew PdxFieldType(fieldName, className, (Byte)typeId,
current, true, -1, m_varLenFieldIdx);
m_pdxFieldTypes->Add(pfType);
//this will make sure one can't add same field name
m_fieldNameVsPdxType->Add(fieldName, pfType);
}
void PdxType::ToData(DataOutput^ output)
{
//defaulf java Dataserializable require this
output->WriteByte(static_cast<int8_t>(DSCode::DataSerializable));
output->WriteByte(static_cast<int8_t>(DSCode::Class));
output->WriteObject((Object^)m_javaPdxClass);
//pdx type
output->WriteString(m_className);
output->WriteBoolean(m_noJavaClass);
output->WriteInt32(m_geodeTypeId);
output->WriteInt32(m_varLenFieldIdx);
output->WriteArrayLen(m_pdxFieldTypes->Count);
for (int i = 0; i < m_pdxFieldTypes->Count; i++)
{
m_pdxFieldTypes[i]->ToData(output);
}
}
void PdxType::FromData(DataInput^ input)
{
//defaulf java Dataserializable require this
Byte val = input->ReadByte();//DS
Byte val1 = input->ReadByte();//class
input->ReadObject();//classname
m_className = input->ReadString();
//Object^ pdxObject = Serializable::GetPdxType(m_className);
// m_pdxDomainType = pdxObject->GetType();
/*PdxWrapper^ pdxWrapper = dynamic_cast<PdxWrapper^>(pdxObject);
if(pdxWrapper == nullptr)
m_pdxDomainType = pdxObject->GetType();
else
m_pdxDomainType = pdxWrapper->GetObject()->GetType();*/
//Log::Debug("PdxType::FromData " + m_className);
m_noJavaClass = input->ReadBoolean();
m_geodeTypeId = input->ReadInt32();
m_varLenFieldIdx = input->ReadInt32();
int len = input->ReadArrayLen();
bool foundVarLenType = false;
for (int i = 0; i < len; i++)
{
PdxFieldType^ pft = gcnew PdxFieldType();
pft->FromData(input);
m_pdxFieldTypes->Add(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(input->Cache);
}
void PdxType::InitializeType(Cache^ cache)
{
initRemoteToLocal(cache);//for writing
initLocalToRemote(cache);//for reading
generatePositionMap();
}
Int32 PdxType::GetFieldPosition(String^ fieldName, System::Byte* offsetPosition, Int32 offsetSize, Int32 pdxStreamlen)
{
PdxFieldType^ pft = nullptr;
m_fieldNameVsPdxType->TryGetValue(fieldName, pft);
if (pft != nullptr)
{
if (pft->IsVariableLengthType)
return variableLengthFieldPosition(pft, offsetPosition, offsetSize, pdxStreamlen);
else
return fixedLengthFieldPosition(pft, offsetPosition, offsetSize, pdxStreamlen);
}
return -1;
}
Int32 PdxType::GetFieldPosition(Int32 fieldIdx, System::Byte* offsetPosition, Int32 offsetSize, Int32 pdxStreamlen)
{
PdxFieldType^ pft = m_pdxFieldTypes[fieldIdx];
if (pft != nullptr)
{
if (pft->IsVariableLengthType)
return variableLengthFieldPosition(pft, offsetPosition, offsetSize, pdxStreamlen);
else
return fixedLengthFieldPosition(pft, offsetPosition, offsetSize, pdxStreamlen);
}
return -1;
}
Int32 PdxType::variableLengthFieldPosition(PdxFieldType^ varLenField, System::Byte* offsetPosition, Int32 offsetSize, Int32 pdxStreamlen)
{
int seqId = varLenField->SequenceId;
int offset = varLenField->VarLenOffsetIndex;
if (offset == -1)
return /*first var len field*/ varLenField->RelativeOffset;
else
{
//we write offset from behind
return PdxHelper::ReadInt(offsetPosition + (m_numberOfVarLenFields - offset - 1)*offsetSize, offsetSize);
}
}
Int32 PdxType::fixedLengthFieldPosition(PdxFieldType^ fixLenField, System::Byte* offsetPosition, Int32 offsetSize, Int32 pdxStreamlen)
{
int seqId = fixLenField->SequenceId;
int offset = fixLenField->VarLenOffsetIndex;
if (fixLenField->RelativeOffset >= 0)
{
//starting fields
return fixLenField->RelativeOffset;
}
else if (offset == -1) //Pdx length
{
//there is no var len field so just subtracts relative offset from behind
return pdxStreamlen + fixLenField->RelativeOffset;
}
else
{
//need to read offset and then subtract relative offset
return PdxHelper::ReadInt(offsetPosition +
(m_numberOfVarLenFields - offset - 1)*offsetSize,
offsetSize)
+ fixLenField->RelativeOffset;
}
}
PdxType^ PdxType::isLocalTypeContains(PdxType^ otherType)
{
if (m_pdxFieldTypes->Count >= otherType->m_pdxFieldTypes->Count)
{
return isContains(this, otherType);
}
return nullptr;
}
PdxType^ PdxType::isRemoteTypeContains(PdxType^ remoteType)
{
if (m_pdxFieldTypes->Count <= remoteType->m_pdxFieldTypes->Count)
{
return isContains(remoteType, this);
}
return nullptr;
}
PdxType^ PdxType::MergeVersion(PdxType^ otherVersion)
{
int nTotalFields = otherVersion->m_pdxFieldTypes->Count;
PdxType^ contains = nullptr;
if (isLocalTypeContains(otherVersion) != nullptr)
return this;
if (isRemoteTypeContains(otherVersion) != nullptr)
return otherVersion;
//need to create new one, clone of local
PdxType^ newone = clone();
int varLenFields = newone->m_numberOfVarLenFields;
for each(PdxFieldType^ tmp in otherVersion->m_pdxFieldTypes)
{
bool found = false;
for each(PdxFieldType^ tmpNew in newone->m_pdxFieldTypes)
{
if (tmpNew->Equals(tmp))
{
found = true;
break;
}
}
if (!found)
{
PdxFieldType^ newFt = gcnew PdxFieldType(tmp->FieldName,
tmp->ClassName,
tmp->TypeId,
newone->m_pdxFieldTypes->Count,//sequence id
tmp->IsVariableLengthType,
tmp->Size,
(tmp->IsVariableLengthType ? varLenFields++/*it increase after that*/ : 0));
newone->m_pdxFieldTypes->Add(newFt);//fieldnameVsPFT will happen after that
}
}
newone->m_numberOfVarLenFields = varLenFields;
if (varLenFields > 0)
newone->m_varLenFieldIdx = varLenFields;
//need to keep all versions in local version
//m_otherVersions->Add(newone);
return newone;
}
PdxType^ PdxType::isContains(PdxType^ first, PdxType^ second)
{
int j = 0;
for (int i = 0; i < second->m_pdxFieldTypes->Count; i++)
{
PdxFieldType^ secondPdt = second->m_pdxFieldTypes[i];
bool matched = false;
for (; j < first->m_pdxFieldTypes->Count; j++)
{
PdxFieldType^ firstPdt = first->m_pdxFieldTypes[j];
if (firstPdt->Equals(secondPdt))
{
matched = true;
break;
}
}
if (!matched)
return nullptr;
}
return first;
}
PdxType^ PdxType::clone()
{
PdxType^ newone = gcnew PdxType(m_className, false);
newone->m_geodeTypeId = 0;
newone->m_numberOfVarLenFields = m_numberOfVarLenFields;
for each(PdxFieldType^ tmp in m_pdxFieldTypes)
{
newone->m_pdxFieldTypes->Add(tmp);
}
return newone;
}
array<int>^ PdxType::GetLocalToRemoteMap(Cache^ cache)
{
if (m_localToRemoteFieldMap != nullptr)
return m_localToRemoteFieldMap;
msclr::lock lockInstance(m_lockObj);
if (m_localToRemoteFieldMap != nullptr)
return m_localToRemoteFieldMap;
initLocalToRemote(cache);
return m_localToRemoteFieldMap;
}
array<int>^ PdxType::GetRemoteToLocalMap(Cache^ cache)
{
//return m_remoteToLocalFieldMap;
if (m_remoteToLocalFieldMap != nullptr)
return m_remoteToLocalFieldMap;
msclr::lock lockInstance(m_lockObj);
if (m_remoteToLocalFieldMap != nullptr)
return m_remoteToLocalFieldMap;
initRemoteToLocal(cache);
return m_remoteToLocalFieldMap;
}
/*
* this is write data on remote type(this will always have all fields)
*/
void PdxType::initRemoteToLocal(Cache^ cache)
{
//get local type from type Registry and then map local fields.
//need to generate static map
PdxType^ localPdxType = cache->GetPdxTypeRegistry()->GetLocalPdxType(m_className);
m_numberOfFieldsExtra = 0;
if (localPdxType != nullptr)
{
IList<PdxFieldType^>^ localPdxFields = localPdxType->m_pdxFieldTypes;
Int32 fieldIdx = 0;
m_remoteToLocalFieldMap = gcnew array<Int32>(m_pdxFieldTypes->Count);
for each(PdxFieldType^ remotePdxField in m_pdxFieldTypes)
{
bool found = false;
for each(PdxFieldType^ localPdxfield in localPdxFields)
{
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->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(Cache^ cache)
{
PdxType^ localPdxType = cache->GetPdxTypeRegistry()->GetLocalPdxType(m_className);
if (localPdxType != nullptr)
{
//Log::Debug("In initLocalToRemote: " + m_geodeTypeId);
IList<PdxFieldType^>^ localPdxFields = localPdxType->m_pdxFieldTypes;
Int32 fieldIdx = 0;
//type which need to read/write should control local type
m_localToRemoteFieldMap = gcnew array<Int32>(localPdxType->m_pdxFieldTypes->Count);
for (int i = 0; i < m_localToRemoteFieldMap->Length && i < m_pdxFieldTypes->Count; i++)
{
if (localPdxFields[fieldIdx]->Equals(m_pdxFieldTypes[i]))
{
//fields are in same order, we can read as it is
m_localToRemoteFieldMap[fieldIdx++] = -2;
}
else
break;
}
for (; fieldIdx < m_localToRemoteFieldMap->Length;)
{
PdxFieldType^ localPdxField = localPdxType->m_pdxFieldTypes[fieldIdx];
bool found = false;
for each(PdxFieldType^ remotePdxfield in m_pdxFieldTypes)
{
if (localPdxField->Equals(remotePdxfield))
{
found = true;
//store pdxfield type position to get the offset quickly
m_localToRemoteFieldMap[fieldIdx++] = remotePdxfield->SequenceId;
break;
}
}
if (!found)
{
//local field is not in remote type
m_localToRemoteFieldMap[fieldIdx++] = -1;
}
}
}
}
void PdxType::generatePositionMap()
{
//1. all static fields offsets
//--read next var len offset and subtract offset
//--if no var len then take length of stream - (len of offsets)
//2. there is no offser for first var len field
bool foundVarLen = false;
int lastVarLenSeqId = 0;
int prevFixedSizeOffsets = 0;
//set offsets from back first
PdxFieldType^ previousField = nullptr;
for (int i = m_pdxFieldTypes->Count - 1; i >= 0; i--)
{
PdxFieldType^ tmpft = m_pdxFieldTypes[i];
m_fieldNameVsPdxType[tmpft->FieldName] = tmpft;
if (tmpft->IsVariableLengthType)
{
tmpft->VarLenOffsetIndex = tmpft->VarLenFieldIdx;
tmpft->RelativeOffset = 0;
foundVarLen = true;
lastVarLenSeqId = tmpft->VarLenFieldIdx;
}
else
{
if (foundVarLen)
{
tmpft->VarLenOffsetIndex = lastVarLenSeqId;
//relative offset is subtracted from var len offsets
tmpft->RelativeOffset = (-tmpft->Size + previousField->RelativeOffset);
}
else
{
tmpft->VarLenOffsetIndex = -1;//Pdx header length
//relative offset is subtracted from var len offsets
tmpft->RelativeOffset = -tmpft->Size;
if (previousField != nullptr)//boundary condition
tmpft->RelativeOffset = (-tmpft->Size + previousField->RelativeOffset);
}
}
previousField = tmpft;
}
foundVarLen = false;
prevFixedSizeOffsets = 0;
//now do optimization till you don't fine var len
for (int i = 0; i < m_pdxFieldTypes->Count && !foundVarLen; i++)
{
PdxFieldType^ tmpft = m_pdxFieldTypes[i];
if (tmpft->IsVariableLengthType)
{
tmpft->VarLenOffsetIndex = -1;//first var len field
tmpft->RelativeOffset = prevFixedSizeOffsets;
foundVarLen = true;
}
else
{
tmpft->VarLenOffsetIndex = 0;//no need to read offset
tmpft->RelativeOffset = prevFixedSizeOffsets;
prevFixedSizeOffsets += tmpft->Size;
}
}
}
bool PdxType::Equals(Object^ otherObj)
{
if (otherObj == nullptr)
return false;
PdxType^ ot = dynamic_cast<PdxType^>(otherObj);
if (ot == nullptr)
return false;
if (ot == this)
return true;
if (ot->m_pdxFieldTypes->Count != m_pdxFieldTypes->Count)
return false;
for (int i = 0; i < m_pdxFieldTypes->Count; i++)
{
if (!ot->m_pdxFieldTypes[i]->Equals(m_pdxFieldTypes[i]))
return false;
}
return true;
}
Int32 PdxType::GetHashCode()
{
int hash = m_cachedHashcode;
if (hash == 0)
{
hash = 1;
hash = hash * 31 + m_className->GetHashCode();
for (int i = 0; i < m_pdxFieldTypes->Count; i++)
{
hash = hash * 31 + m_pdxFieldTypes[i]->GetHashCode();
}
if (hash == 0)
{
hash = 1;
}
m_cachedHashcode = hash;
}
return m_cachedHashcode;
}
} // namespace Internal
} // namespace Client
} // namespace Geode
} // namespace Apache