-
Notifications
You must be signed in to change notification settings - Fork 131
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
nfs: introduce PoolDeviceMap for pool to deviceid mapping
Acked-by: Karsten Schwank Target: master Require-book: no Require-notes: no
- Loading branch information
Showing
3 changed files
with
197 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91 changes: 91 additions & 0 deletions
91
modules/dcache/src/main/java/org/dcache/chimera/nfsv41/door/PoolDeviceMap.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package org.dcache.chimera.nfsv41.door; | ||
|
||
import com.google.common.collect.ImmutableSet; | ||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.concurrent.locks.ReentrantReadWriteLock; | ||
import org.dcache.nfs.v4.xdr.deviceid4; | ||
import org.dcache.chimera.nfsv41.door.NFSv41Door.PoolDS; | ||
|
||
/** | ||
* A mapping between pool name, nfs device id and pool's ip addresses. | ||
*/ | ||
public class PoolDeviceMap { | ||
|
||
/** | ||
* dCache-friendly NFS device id to pool name mapping | ||
*/ | ||
private final Map<String, PoolDS> _poolNameToIpMap = new HashMap<>(); | ||
|
||
/** | ||
* All known devices | ||
*/ | ||
private final Map<deviceid4, PoolDS> _deviceMap = new HashMap<>(); | ||
|
||
/* | ||
* as there are mostly reads, use read-write locks to increase concurrency | ||
*/ | ||
private final ReentrantReadWriteLock _lock = new ReentrantReadWriteLock(); | ||
private final ReentrantReadWriteLock.ReadLock _rlock = _lock.readLock(); | ||
private final ReentrantReadWriteLock.WriteLock _wlock = _lock.writeLock(); | ||
|
||
void add(String poolName, PoolDS device) { | ||
_wlock.lock(); | ||
try { | ||
PoolDS oldDevice = _poolNameToIpMap.put(poolName, device); | ||
// remove dead entry | ||
if (oldDevice != null) { | ||
_deviceMap.remove(oldDevice.getDeviceId()); | ||
} | ||
_deviceMap.put(device.getDeviceId(), device); | ||
} finally { | ||
_wlock.unlock(); | ||
} | ||
} | ||
|
||
Collection<PoolDS> getDevices() { | ||
_rlock.lock(); | ||
try { | ||
return ImmutableSet.copyOf(_poolNameToIpMap.values()); | ||
} finally { | ||
_rlock.unlock(); | ||
} | ||
} | ||
|
||
Collection<deviceid4> getDeviceIds() { | ||
_rlock.lock(); | ||
try { | ||
return ImmutableSet.copyOf(_deviceMap.keySet()); | ||
} finally { | ||
_rlock.unlock(); | ||
} | ||
} | ||
|
||
synchronized PoolDS getByPoolName(String name) { | ||
_rlock.lock(); | ||
try { | ||
return _poolNameToIpMap.get(name); | ||
} finally { | ||
_rlock.unlock(); | ||
} | ||
} | ||
|
||
synchronized PoolDS getByDeviceId(deviceid4 deviceId) { | ||
_rlock.lock(); | ||
try { | ||
return _deviceMap.get(deviceId); | ||
} finally { | ||
_rlock.unlock(); | ||
} | ||
} | ||
|
||
synchronized Collection<Map.Entry<String,PoolDS>> getEntries() { | ||
_rlock.lock(); | ||
try { | ||
return ImmutableSet.copyOf(_poolNameToIpMap.entrySet()); | ||
} finally { | ||
_rlock.unlock(); | ||
} | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
modules/dcache/src/test/java/org/dcache/chimera/nfsv41/door/PoolDeviceMapTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package org.dcache.chimera.nfsv41.door; | ||
|
||
import java.net.InetSocketAddress; | ||
import java.net.UnknownHostException; | ||
import org.dcache.nfs.v4.RoundRobinStripingPattern; | ||
import org.dcache.nfs.v4.StripingPattern; | ||
import org.dcache.nfs.v4.xdr.deviceid4; | ||
import org.dcache.nfs.v4.xdr.nfs4_prot; | ||
import org.dcache.utils.Bytes; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
|
||
import static org.junit.Assert.assertNull; | ||
import static org.junit.Assert.assertNotNull; | ||
|
||
/** | ||
* | ||
* @author tigran | ||
*/ | ||
public class PoolDeviceMapTest { | ||
|
||
private final StripingPattern<InetSocketAddress[]> _stripingPattern | ||
= new RoundRobinStripingPattern<>(); | ||
|
||
private PoolDeviceMap _poolDeviceMap; | ||
|
||
@Before | ||
public void setUp() { | ||
_poolDeviceMap = new PoolDeviceMap(); | ||
} | ||
|
||
@Test | ||
public void testGetMissingById() { | ||
deviceid4 id = deviceidOf(1); | ||
NFSv41Door.PoolDS ds = _poolDeviceMap.getByDeviceId(id); | ||
assertNull("Got not existing", ds); | ||
} | ||
|
||
@Test | ||
public void testGetMissingByName() { | ||
String name = "somePool"; | ||
NFSv41Door.PoolDS ds = _poolDeviceMap.getByPoolName(name); | ||
assertNull("Got not existing", ds); | ||
} | ||
|
||
@Test | ||
public void testGetExisting() throws UnknownHostException { | ||
String name = "somePool"; | ||
deviceid4 id1 = deviceidOf(1); | ||
InetSocketAddress[] ip = new InetSocketAddress[]{new InetSocketAddress(0)}; | ||
|
||
NFSv41Door.PoolDS ds1 = new NFSv41Door.PoolDS(id1, _stripingPattern, ip); | ||
|
||
_poolDeviceMap.add(name, ds1); | ||
NFSv41Door.PoolDS ds; | ||
ds = _poolDeviceMap.getByDeviceId(id1); | ||
assertNotNull("Can't get existing by id", ds); | ||
|
||
ds = _poolDeviceMap.getByPoolName(name); | ||
assertNotNull("Can't get existing by name", ds); | ||
} | ||
|
||
@Test | ||
public void testUpdateExisting() throws UnknownHostException { | ||
String name = "somePool"; | ||
deviceid4 id1 = deviceidOf(1); | ||
deviceid4 id2 = deviceidOf(2); | ||
InetSocketAddress[] ip = new InetSocketAddress[]{new InetSocketAddress(0)}; | ||
|
||
NFSv41Door.PoolDS ds1 = new NFSv41Door.PoolDS(id1, _stripingPattern, ip); | ||
NFSv41Door.PoolDS ds2 = new NFSv41Door.PoolDS(id2, _stripingPattern, ip); | ||
|
||
_poolDeviceMap.add(name, ds1); | ||
_poolDeviceMap.add(name, ds2); | ||
|
||
NFSv41Door.PoolDS ds; | ||
ds = _poolDeviceMap.getByDeviceId(id1); | ||
assertNull("Update did not invalidate old id", ds); | ||
|
||
ds = _poolDeviceMap.getByPoolName(name); | ||
assertNotNull("Can't get updated by name", ds); | ||
} | ||
|
||
private static deviceid4 deviceidOf(int id) { | ||
byte[] deviceidBytes = new byte[nfs4_prot.NFS4_DEVICEID4_SIZE]; | ||
Bytes.putInt(deviceidBytes, 0, id); | ||
|
||
return new deviceid4(deviceidBytes); | ||
} | ||
} |