blob: 76f2e519e0da1c7a27cbd47c70415357ccc34dbe [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 "ignite/impl/handle_registry.h"
using namespace ignite::common::concurrent;
namespace ignite
{
namespace impl
{
HandleRegistrySegment::HandleRegistrySegment() :
map(),
mux()
{
// No-op.
}
HandleRegistrySegment::~HandleRegistrySegment()
{
// No-op.
}
SharedPointer<void> HandleRegistrySegment::Get(int64_t hnd)
{
typedef std::map<int64_t, SharedPointer<void> > Map;
CsLockGuard guard(mux);
Map::const_iterator it = map.find(hnd);
if (it == map.end())
return SharedPointer<void>();
return it->second;
}
void HandleRegistrySegment::Put(int64_t hnd, const SharedPointer<void>& entry)
{
CsLockGuard guard(mux);
map[hnd] = entry;
}
void HandleRegistrySegment::Remove(int64_t hnd)
{
CsLockGuard guard(mux);
map.erase(hnd);
}
void HandleRegistrySegment::Clear()
{
CsLockGuard guard(mux);
map.clear();
}
HandleRegistry::HandleRegistry(int32_t fastCap, int32_t slowSegmentCnt) :
fastCap(fastCap),
fastCtr(0),
fast(new SharedPointer<void>[fastCap]),
slowSegmentCnt(slowSegmentCnt),
slowCtr(fastCap),
slow(new HandleRegistrySegment*[slowSegmentCnt]),
closed(0)
{
for (int32_t i = 0; i < fastCap; i++)
fast[i] = SharedPointer<void>();
for (int32_t i = 0; i < slowSegmentCnt; i++)
slow[i] = new HandleRegistrySegment();
Memory::Fence();
}
HandleRegistry::~HandleRegistry()
{
Close();
delete[] fast;
for (int i = 0; i < slowSegmentCnt; i++)
delete slow[i];
delete[] slow;
}
int64_t HandleRegistry::Allocate(const SharedPointer<void>& target)
{
return Allocate0(target, false, false);
}
int64_t HandleRegistry::AllocateCritical(const SharedPointer<void>& target)
{
return Allocate0(target, true, false);
}
int64_t HandleRegistry::AllocateSafe(const SharedPointer<void>& target)
{
return Allocate0(target, false, true);
}
int64_t HandleRegistry::AllocateCriticalSafe(const SharedPointer<void>& target)
{
return Allocate0(target, true, true);
}
void HandleRegistry::Release(int64_t hnd)
{
if (hnd < 0)
return;
else if (hnd < fastCap)
fast[static_cast<int32_t>(hnd)] = SharedPointer<void>();
else
{
HandleRegistrySegment* segment = slow[hnd % slowSegmentCnt];
segment->Remove(hnd);
}
Memory::Fence();
}
SharedPointer<void> HandleRegistry::Get(int64_t hnd)
{
Memory::Fence();
if (hnd < fastCap)
return fast[static_cast<int32_t>(hnd)];
else
{
HandleRegistrySegment* segment = slow[hnd % slowSegmentCnt];
return segment->Get(hnd);
}
}
void HandleRegistry::Close()
{
if (Atomics::CompareAndSet32(&closed, 0, 1))
{
// Cleanup fast-path handles.
for (int32_t i = 0; i < fastCap; i++)
fast[i] = SharedPointer<void>();
// Cleanup slow-path handles.
for (int32_t i = 0; i < slowSegmentCnt; i++)
slow[i]->Clear();
}
}
int64_t HandleRegistry::Allocate0(const SharedPointer<void>& target, bool critical, bool safe)
{
// Check closed state.
Memory::Fence();
if (closed == 1)
return -1;
// Try allocating entry on critical path.
if (critical)
{
if (fastCtr < fastCap)
{
int32_t fastIdx = Atomics::IncrementAndGet32(&fastCtr) - 1;
if (fastIdx < fastCap)
{
fast[fastIdx] = target;
// Double-check for closed state if safe mode is on.
Memory::Fence();
if (safe && closed == 1)
{
fast[fastIdx] = SharedPointer<void>();
return -1;
}
else
return fastIdx;
}
}
}
// Either allocating on slow-path, or fast-path can no longer accomodate more entries.
int64_t slowIdx = Atomics::IncrementAndGet64(&slowCtr) - 1;
HandleRegistrySegment* segment = slow[slowIdx % slowSegmentCnt];
segment->Put(slowIdx, target);
// Double-check for closed state if safe mode is on.
Memory::Fence();
if (safe && closed == 1)
{
segment->Remove(slowIdx);
return -1;
}
return slowIdx;
}
}
}