Skip to content

Commit

Permalink
Fix performance problem by caching unix group and user names (fixes #109
Browse files Browse the repository at this point in the history
) (#135)
  • Loading branch information
gnodet authored Jul 17, 2024
1 parent 412238d commit 5a52f6e
Showing 1 changed file with 57 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,18 @@

import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.nio.file.attribute.PosixFilePermission;
import java.security.Principal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;

/*
* File attributes
Expand Down Expand Up @@ -68,6 +70,12 @@ public class FileAttributes implements PlexusIoResourceAttributes {

private final FileTime lastModifiedTime;

private static final Map<FileSystem, Map<Integer, String>> UIDS_CACHE =
Collections.synchronizedMap(new WeakHashMap<>());

private static final Map<FileSystem, Map<Integer, String>> GIDS_CACHE =
Collections.synchronizedMap(new WeakHashMap<>());

/**
* @deprecated use {@link #FileAttributes(File)} and remove the unused userCache and groupCache parameters
*/
Expand All @@ -79,32 +87,64 @@ public FileAttributes(
}

public FileAttributes(@Nonnull File file) throws IOException {
this(file, false);
this(file.toPath(), false);
}

public FileAttributes(@Nonnull File file, boolean followLinks) throws IOException {
this(file.toPath(), followLinks);
}

private static Map<Integer, String> getUserCache(FileSystem fs) {
return UIDS_CACHE.computeIfAbsent(fs, f -> new ConcurrentHashMap<>());
}

private static Map<Integer, String> getGroupCache(FileSystem fs) {
return GIDS_CACHE.computeIfAbsent(fs, f -> new ConcurrentHashMap<>());
}

public FileAttributes(@Nonnull Path path, boolean followLinks) throws IOException {
LinkOption[] options = followLinks ? FOLLOW_LINK_OPTIONS : NOFOLLOW_LINK_OPTIONS;
Path path = file.toPath();
Set<String> views = path.getFileSystem().supportedFileAttributeViews();
String names;
if (views.contains("unix")) {
names = "unix:*";
names =
"unix:gid,uid,isSymbolicLink,isRegularFile,isDirectory,isOther,mode,permissions,size,lastModifiedTime";
} else if (views.contains("posix")) {
names = "posix:*";
} else {
names = "basic:*";
}
Map<String, Object> attrs = Files.readAttributes(path, names, options);
if (!attrs.containsKey("group") && !attrs.containsKey("owner") && views.contains("owner")) {
Map<String, Object> ownerAttrs = Files.readAttributes(path, "owner:*", options);
Map<String, Object> newAttrs = new HashMap<>(attrs);
newAttrs.putAll(ownerAttrs);
attrs = newAttrs;
}
this.groupId = (Integer) attrs.get("gid");
this.groupName = attrs.containsKey("group") ? ((Principal) attrs.get("group")).getName() : null;
if (attrs.containsKey("group")) {
this.groupName = ((Principal) attrs.get("group")).getName();
} else if (this.groupId != null) {
Map<Integer, String> cache = getGroupCache(path.getFileSystem());
String name = cache.get(this.groupId);
if (name == null) {
name = getPrincipalName(path, "unix:group");
cache.put(this.groupId, name);
}
this.groupName = name;
} else {
this.groupName = null;
}
this.userId = (Integer) attrs.get("uid");
this.userName = attrs.containsKey("owner") ? ((Principal) attrs.get("owner")).getName() : null;
if (attrs.containsKey("owner")) {
this.userName = ((Principal) attrs.get("owner")).getName();
} else if (this.userId != null) {
Map<Integer, String> cache = getUserCache(path.getFileSystem());
String name = cache.get(this.userId);
if (name == null) {
name = getPrincipalName(path, "unix:owner");
cache.put(this.userId, name);
}
this.userName = name;
} else if (views.contains("owner")) {
this.userName = getPrincipalName(path, "owner:owner");
} else {
this.userName = null;
}
this.symbolicLink = (Boolean) attrs.get("isSymbolicLink");
this.regularFile = (Boolean) attrs.get("isRegularFile");
this.directory = (Boolean) attrs.get("isDirectory");
Expand All @@ -120,6 +160,11 @@ public FileAttributes(@Nonnull File file, boolean followLinks) throws IOExceptio
this.lastModifiedTime = (FileTime) attrs.get("lastModifiedTime");
}

private static String getPrincipalName(Path path, String attribute) throws IOException {
Object owner = Files.getAttribute(path, attribute, LinkOption.NOFOLLOW_LINKS);
return ((Principal) owner).getName();
}

public FileAttributes(
@Nullable Integer userId,
String userName,
Expand Down

0 comments on commit 5a52f6e

Please sign in to comment.