Skip to content

Commit e0176ff

Browse files
committed
core: Reduce fileId byte[] usage; improve and encourage use of Opaque
We currently use byte[] in many places where we actually convert them back into Base64 (and sometimes Base16) encoded strings, especially around locking. This is suboptimal. We also pass byte[] directly, which allows direct manipulation, which is also not good. Deprecate direct use of Inode.getFileId. Return an "Opaque" for locking purposes as well (but allow them to be separate from the Opaque fileId key to allow coarser locking). Provide default implementations of the Opaque-variants in LockManager. Changes to AbstractLockManager etc. follow in a separate commit. Change the Base16-encoded file names in FsCache to the same Base64-encoded locking key. Make Opaque immutable-ish (deprecate constructor and getOpaque() method that allows direct manipulation of the underlying byte[] but keep them in for now for backwards compatibility), and add a cached byte[]-to-Base64 string which is constructed only upon demand. Related: #149 Signed-off-by: Christian Kohlschütter <[email protected]>
1 parent 28fcfe4 commit e0176ff

File tree

7 files changed

+64
-9
lines changed

7 files changed

+64
-9
lines changed

core/src/main/java/org/dcache/nfs/util/Opaque.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import java.io.Serializable;
2323
import java.util.Arrays;
24+
import java.util.Base64;
2425

2526
import com.google.common.io.BaseEncoding;
2627

@@ -32,15 +33,33 @@ public class Opaque implements Serializable {
3233
private static final long serialVersionUID = 1532238396149112674L;
3334

3435
private final byte[] _opaque;
36+
private String base64 = null;
3537

38+
public static Opaque forBytes(byte[] bytes) {
39+
return new Opaque(bytes.clone());
40+
}
41+
42+
@Deprecated(forRemoval = true)
3643
public Opaque(byte[] opaque) {
3744
_opaque = opaque;
3845
}
3946

47+
@Deprecated(forRemoval = true)
4048
public byte[] getOpaque() {
4149
return _opaque;
4250
}
4351

52+
public byte[] asBytes() {
53+
return _opaque.clone();
54+
}
55+
56+
public String getBase64() {
57+
if (base64 == null) {
58+
base64 = Base64.getEncoder().withoutPadding().encodeToString(_opaque);
59+
}
60+
return base64;
61+
}
62+
4463
@Override
4564
public int hashCode() {
4665
return Arrays.hashCode(_opaque);
@@ -58,6 +77,12 @@ public boolean equals(Object o) {
5877
return Arrays.equals(_opaque, ((Opaque) o)._opaque);
5978
}
6079

80+
/**
81+
* Returns a (potentially non-stable) debug string.
82+
*
83+
* @see #getBase64()
84+
*/
85+
@Deprecated
6186
@Override
6287
public String toString() {
6388
StringBuilder sb = new StringBuilder();

core/src/main/java/org/dcache/nfs/v4/OperationLOCK.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ public void process(CompoundContext context, nfs_resop4 result) throws ChimeraNF
118118

119119
NlmLock lock = new NlmLock(lockOwner, _args.oplock.locktype, _args.oplock.offset.value,
120120
_args.oplock.length.value);
121-
context.getLm().lock(inode.getFileId(), lock);
121+
context.getLm().lock(inode.getLockKey(), lock);
122122

123123
// ensure, that on close locks will be released
124124
lock_state.addDisposeListener(s -> {
125-
context.getLm().unlockIfExists(inode.getFileId(), lock);
125+
context.getLm().unlockIfExists(inode.getLockKey(), lock);
126126
});
127127

128128
// FIXME: we might run into race condition, thus updating sedid must be fenced!

core/src/main/java/org/dcache/nfs/v4/OperationLOCKT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public void process(CompoundContext context, nfs_resop4 result) throws IOExcepti
8585

8686
NlmLock lock = new NlmLock(lockOwner, _args.oplockt.locktype, _args.oplockt.offset.value,
8787
_args.oplockt.length.value);
88-
context.getLm().test(inode.getFileId(), lock);
88+
context.getLm().test(inode.getLockKey(), lock);
8989

9090
result.oplockt.status = nfsstat.NFS_OK;
9191

core/src/main/java/org/dcache/nfs/v4/OperationLOCKU.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public void process(CompoundContext context, nfs_resop4 result) throws ChimeraNF
7676
NlmLock lock = new NlmLock(lockOwner, _args.oplocku.locktype, _args.oplocku.offset.value,
7777
_args.oplocku.length.value);
7878
try {
79-
context.getLm().unlock(inode.getFileId(), lock);
79+
context.getLm().unlock(inode.getLockKey(), lock);
8080
} catch (LockRangeUnavailabeException e) {
8181
// posix locks allows unlocking of not locked regions
8282
}

core/src/main/java/org/dcache/nfs/v4/nlm/LockManager.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
*/
2020
package org.dcache.nfs.v4.nlm;
2121

22+
import org.dcache.nfs.util.Opaque;
23+
2224
/**
2325
*/
2426
public interface LockManager {
@@ -33,6 +35,10 @@ public interface LockManager {
3335
*/
3436
void lock(byte[] objId, NlmLock lock) throws LockException;
3537

38+
default void lock(Opaque key, NlmLock lock) throws LockException {
39+
lock(key.asBytes(), lock);
40+
}
41+
3642
/**
3743
* Unlock byte range of an {@code objId}.
3844
*
@@ -43,6 +49,10 @@ public interface LockManager {
4349
*/
4450
void unlock(byte[] objId, NlmLock lock) throws LockException;
4551

52+
default void unlock(Opaque key, NlmLock lock) throws LockException {
53+
unlock(key.asBytes(), lock);
54+
}
55+
4656
/**
4757
* Test byte range lock existence for an {@code objId}. Same as {@link #lock}, except that a new lock is not
4858
* created.
@@ -54,11 +64,19 @@ public interface LockManager {
5464
*/
5565
void test(byte[] objId, NlmLock lock) throws LockException;
5666

67+
default void test(Opaque key, NlmLock lock) throws LockException {
68+
test(key.asBytes(), lock);
69+
}
70+
5771
/**
5872
* Like {@link #unlock(byte[], org.dcache.nfs.v4.nlm.NlmLock)}, but does not fail if lock does not exists.
5973
*
6074
* @param objId
6175
* @param lock
6276
*/
6377
void unlockIfExists(byte[] objId, NlmLock lock);
78+
79+
default void unlockIfExists(Opaque key, NlmLock lock) {
80+
unlockIfExists(key.asBytes(), lock);
81+
}
6482
}

core/src/main/java/org/dcache/nfs/vfs/FsCache.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ private static class FileChannelSupplier extends CacheLoader<Inode, FileChannel>
5252

5353
@Override
5454
public FileChannel load(Inode inode) throws IOException {
55-
byte[] fid = inode.getFileId();
56-
String id = BaseEncoding.base16().lowerCase().encode(fid);
55+
String id = inode.getLockKey().getBase64();
5756
File dir = getAndCreateDirectory(id);
5857
File f = new File(dir, id);
5958
return new RandomAccessFile(f, "rw").getChannel();

core/src/main/java/org/dcache/nfs/vfs/Inode.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public Inode(int generation, int exportIdx, int type, byte[] fs_opaque) {
7474
this.generation = generation;
7575
this.exportIdx = exportIdx;
7676
this.type = type;
77-
this.opaqueKey = new Opaque(fs_opaque.clone());
77+
this.opaqueKey = Opaque.forBytes(fs_opaque);
7878

7979
this.nfsHandle = buildNfsHandle(fs_opaque);
8080
}
@@ -111,7 +111,7 @@ public Inode(byte[] bytes) {
111111
int olen = (int) b.get();
112112
byte[] fs_opaque = new byte[olen];
113113
b.get(fs_opaque);
114-
this.opaqueKey = new Opaque(fs_opaque);
114+
this.opaqueKey = Opaque.forBytes(fs_opaque);
115115

116116
this.nfsHandle = bytes.clone();
117117
}
@@ -144,8 +144,21 @@ public static Inode forFile(byte[] bytes) {
144144
return new Inode(0, 0, 0, bytes);
145145
}
146146

147+
@Deprecated(forRemoval = true)
147148
public byte[] getFileId() {
148-
return opaqueKey.getOpaque().clone();
149+
return opaqueKey.asBytes();
150+
}
151+
152+
/**
153+
* Returns a locking-key referring to the underlying inode/file referred to by this instance, or a superset,
154+
* suitable for {@link org.dcache.nfs.v4.nlm.LockManager} etc.
155+
* <p>
156+
* This may or may not be equal to {@link #getFileIdKey()}.
157+
*
158+
* @return The locking key for file referred to by this inode.
159+
*/
160+
public Opaque getLockKey() {
161+
return opaqueKey;
149162
}
150163

151164
/**

0 commit comments

Comments
 (0)