Skip to content

Commit

Permalink
Issue #50 Implement offheap-resource provider
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisdennis committed Mar 18, 2016
1 parent c48e8bd commit 9fcccdc
Show file tree
Hide file tree
Showing 6 changed files with 437 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* The contents of this file are subject to the Terracotta Public 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://terracotta.org/legal/terracotta-public-license.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Covered Software is OffHeap Resource.
*
* The Initial Developer of the Covered Software is
* Terracotta, Inc., a Software AG company
*/

package org.terracotta.offheapresource;

import java.util.concurrent.atomic.AtomicLong;

public class OffHeapResource {

private final AtomicLong remaining;

OffHeapResource(long size) {
if (size < 0) {
throw new IllegalArgumentException("Resource size cannot be negative");
} else {
this.remaining = new AtomicLong(size);
}
}

public boolean allocate(long size) {
if (size < 0) {
throw new IllegalArgumentException("Allocation size cannot be negative");
} else {
for (long current = remaining.get(); current >= size; current = remaining.get()) {
if (remaining.compareAndSet(current, current - size)) {
return true;
}
}
return false;
}
}

public void free(long size) {
if (size < 0) {
throw new IllegalArgumentException("Freed size cannot be negative");
} else {
remaining.addAndGet(size);
}
}

public long available() {
return remaining.get();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* The contents of this file are subject to the Terracotta Public 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://terracotta.org/legal/terracotta-public-license.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Covered Software is OffHeap Resource.
*
* The Initial Developer of the Covered Software is
* Terracotta, Inc., a Software AG company
*/

package org.terracotta.offheapresource;

import org.terracotta.entity.ServiceConfiguration;

/**
*
* @author cdennis
*/
public final class OffHeapResourceIdentifier implements ServiceConfiguration<OffHeapResource> {

private final String name;

public static OffHeapResourceIdentifier identifier(String name) {
return new OffHeapResourceIdentifier(name);
}

private OffHeapResourceIdentifier(String name) {
if (name == null) {
throw new NullPointerException("Name cannot be null");
} else {
this.name = name;
}
}

@Override
public int hashCode() {
return name.hashCode();
}

@Override
public boolean equals(Object obj) {
return (obj instanceof OffHeapResourceIdentifier) && name.equals(((OffHeapResourceIdentifier) obj).name);
}

@Override
public Class<OffHeapResource> getServiceType() {
return OffHeapResource.class;
}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,89 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
* The contents of this file are subject to the Terracotta Public 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://terracotta.org/legal/terracotta-public-license.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Covered Software is OffHeap Resource.
*
* The Initial Developer of the Covered Software is
* Terracotta, Inc., a Software AG company
*/

package org.terracotta.offheapresource;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.terracotta.entity.ServiceConfiguration;
import org.terracotta.entity.ServiceProvider;
import org.terracotta.entity.ServiceProviderConfiguration;
import org.terracotta.offheapresource.config.MemoryUnit;
import org.terracotta.offheapresource.config.ResourceType;

/**
*
* @author cdennis
*/
class OffHeapResourcesProvider implements ServiceProvider {

private final Map<OffHeapResourceIdentifier, OffHeapResource> resources = new HashMap<OffHeapResourceIdentifier, OffHeapResource>();

@Override
public boolean initialize(ServiceProviderConfiguration configuration) {
throw new UnsupportedOperationException();
public synchronized boolean initialize(ServiceProviderConfiguration unknownConfig) {
if (unknownConfig instanceof OffHeapResourcesConfiguration) {
OffHeapResourcesConfiguration configuration = (OffHeapResourcesConfiguration) unknownConfig;
if (resources.isEmpty()) {
for (ResourceType r : configuration.getResources()) {
resources.put(OffHeapResourceIdentifier.identifier(r.getName()), new OffHeapResource(convert(r.getValue(), r.getUnit()).longValueExact()));
}
return true;
} else {
throw new IllegalStateException("Resources already initialized");
}
} else {
return false;
}
}

@Override
public <T> T getService(long consumerID, ServiceConfiguration<T> configuration) {
throw new UnsupportedOperationException();
public <T> T getService(long consumerID, ServiceConfiguration<T> unknownConfiguration) {
if (unknownConfiguration instanceof OffHeapResourceIdentifier) {
OffHeapResourceIdentifier identifier = (OffHeapResourceIdentifier) unknownConfiguration;
return (T) identifier.getServiceType().cast(resources.get(identifier));
} else {
throw new IllegalArgumentException("Unexpected configuration type " + unknownConfiguration.getClass());
}
}

@Override
public Collection<Class<?>> getProvidedServiceTypes() {
throw new UnsupportedOperationException();
return Collections.<Class<?>>singleton(OffHeapResource.class);
}

@Override
public void close() throws IOException {
throw new UnsupportedOperationException();
public void close() {
resources.clear();
}

private static BigInteger convert(BigInteger value, MemoryUnit unit) {
switch (unit) {
case B: return value.shiftLeft(0);
case K_B: return value.shiftLeft(10);
case MB: return value.shiftLeft(20);
case GB: return value.shiftLeft(30);
case TB: return value.shiftLeft(40);
case PB: return value.shiftLeft(50);
}
throw new IllegalArgumentException("Unknown unit " + unit);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* The contents of this file are subject to the Terracotta Public 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://terracotta.org/legal/terracotta-public-license.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Covered Software is OffHeap Resource.
*
* The Initial Developer of the Covered Software is
* Terracotta, Inc., a Software AG company
*/
package org.terracotta.offheapresource;

import static org.hamcrest.core.Is.is;
import org.junit.Test;

import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

public class OffHeapResourceIdentifierTest {

@Test
public void testNullName() {
try {
OffHeapResourceIdentifier.identifier(null);
fail("Expected NullPointerException");
} catch (NullPointerException e) {
//expected
}
}

@Test
public void testServiceType() {
assertThat(OffHeapResourceIdentifier.identifier("foo").getServiceType(), equalTo(OffHeapResource.class));
}

@Test
public void testEquals() {
assertThat(OffHeapResourceIdentifier.identifier("foo").equals(OffHeapResourceIdentifier.identifier("foo")), is(true));
assertThat(OffHeapResourceIdentifier.identifier("foo").equals(OffHeapResourceIdentifier.identifier("bar")), is(false));
}

@Test
public void testHashcode() {
assertThat(OffHeapResourceIdentifier.identifier("foo").hashCode(), is(OffHeapResourceIdentifier.identifier("foo").hashCode()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* The contents of this file are subject to the Terracotta Public 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://terracotta.org/legal/terracotta-public-license.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Covered Software is OffHeap Resource.
*
* The Initial Developer of the Covered Software is
* Terracotta, Inc., a Software AG company
*/

package org.terracotta.offheapresource;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import org.junit.Test;

public class OffHeapResourceTest {

@Test
public void testNegativeResourceSize() {
try {
new OffHeapResource(-1);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
//expected;
}
}

@Test
public void testZeroSizeResourceIsUseless() {
OffHeapResource ohr = new OffHeapResource(0);
assertThat(ohr.allocate(1), is(false));
assertThat(ohr.available(), is(0L));
}

@Test
public void testAllocationReducesSize() {
OffHeapResource ohr = new OffHeapResource(20);
assertThat(ohr.available(), is(20L));
assertThat(ohr.allocate(10), is(true));
assertThat(ohr.available(), is(10L));
}

@Test
public void testNegativeAllocationFails() {
OffHeapResource ohr = new OffHeapResource(20);
try {
ohr.allocate(-1);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
//expected
}
}

@Test
public void testAllocationWhenExhaustedFails() {
OffHeapResource ohr = new OffHeapResource(20);
ohr.allocate(20);
assertThat(ohr.allocate(1), is(false));
assertThat(ohr.available(), is(0L));
}

@Test
public void testFreeIncreasesSize() {
OffHeapResource ohr = new OffHeapResource(20);
ohr.allocate(20);
assertThat(ohr.available(), is(0L));
ohr.free(10);
assertThat(ohr.available(), is(10L));
}

@Test
public void testNegativeFreeFails() {
OffHeapResource ohr = new OffHeapResource(20);
ohr.allocate(10);
try {
ohr.free(-10);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
//expected
}
}
}
Loading

0 comments on commit 9fcccdc

Please sign in to comment.