Skip to content

Commit 2a01b13

Browse files
committed
dcache-webdav: revert improve efficiency of directory listing (14085/14088)
Motivation: See `RT 10505: Problem with webdav PROPFIND request for dirs with symlinks` https://rt.dcache.org/Ticket/Display.html?id=10505 The problem may be more generalized than the discussion suggests. Since we cut off user requests when at the `PERFORMANCE` setting, if the user wants locality, for instance, it fails. Modification: We propose to commit #14082, #14086, and #14087 on top of the reverted base. We will also add a modification to ignore quota requests when the default setting is `PERFORMANCE`. Result: reverts commit 3567dde https://rb.dcache.org/r/14088/ `dcache-webdav: fix incorrect parameter value given to DcacheDirectoryResource constructor` reverts commit 707000c. https://rb.dcache.org/r/14085/ `dcache-webdav: improve efficiency of directory listing – revised` (metalink addition conflicts resolved) Target: master Request: 9.1 Request: 9.0 Request: 8.2 Requires-notes: absolutely Patch: https://rb.dcache.org/r/14101/ Acked-by: Dmitry
1 parent 29f340d commit 2a01b13

5 files changed

Lines changed: 25 additions & 106 deletions

File tree

modules/dcache-webdav/src/main/java/org/dcache/webdav/DcacheDirectoryResource.java

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import static io.milton.property.PropertySource.PropertyAccessibility.READ_ONLY;
44
import static java.nio.charset.StandardCharsets.UTF_8;
5-
import static org.dcache.namespace.FileAttribute.STORAGEINFO;
65

76
import com.google.common.collect.ImmutableSet;
87
import com.google.common.net.MediaType;
@@ -21,7 +20,6 @@
2120
import io.milton.http.LockToken;
2221
import io.milton.http.Range;
2322
import io.milton.http.Request;
24-
import io.milton.http.Response;
2523
import io.milton.http.exceptions.BadRequestException;
2624
import io.milton.http.exceptions.ConflictException;
2725
import io.milton.http.exceptions.NotAuthorizedException;
@@ -49,7 +47,6 @@
4947
import java.util.Map;
5048
import java.util.Optional;
5149
import javax.xml.namespace.QName;
52-
import org.dcache.space.ReservationCaches;
5350
import javax.xml.stream.XMLStreamException;
5451
import org.dcache.vehicles.FileAttributes;
5552
import org.slf4j.Logger;
@@ -94,12 +91,9 @@ private interface EntityWriter {
9491
private final Map<String,MediaType> supportedResponseMediaTypes = Map.of(
9592
"metalink", METALINK_ENTITY_TYPE);
9693

97-
private final boolean _allAttributes;
98-
9994
public DcacheDirectoryResource(DcacheResourceFactory factory,
100-
FsPath path, FileAttributes attributes, boolean allAttributes) {
95+
FsPath path, FileAttributes attributes) {
10196
super(factory, path, attributes);
102-
_allAttributes = allAttributes;
10397
}
10498

10599
@Override
@@ -333,12 +327,6 @@ public LockToken createAndLock(String name, LockTimeout timeout, LockInfo lockIn
333327
return createNullLock();
334328
}
335329

336-
private Optional<String> getWriteToken() {
337-
return _attributes.isDefined(STORAGEINFO)
338-
? ReservationCaches.writeToken(_attributes)
339-
: _factory.lookupWriteToken(_path);
340-
}
341-
342330
@Override
343331
public Object getProperty(QName name) {
344332
Object value = super.getProperty(name);
@@ -349,13 +337,11 @@ public Object getProperty(QName name) {
349337

350338
try {
351339
if (name.equals(QUOTA_AVAILABLE)) {
352-
var maybeToken = getWriteToken();
353-
return _factory.spaceForToken(maybeToken).getAvailableSpaceInBytes();
340+
return _factory.spaceForPath(_path).getAvailableSpaceInBytes();
354341
}
355342

356343
if (name.equals(QUOTA_USED)) {
357-
var maybeToken = getWriteToken();
358-
Space space = _factory.spaceForToken(maybeToken);
344+
Space space = _factory.spaceForPath(_path);
359345
return space.getUsedSizeInBytes() + space.getAllocatedSpaceInBytes();
360346
}
361347
} catch (SpaceException e) {
@@ -369,17 +355,14 @@ public Object getProperty(QName name) {
369355
public PropertyMetaData getPropertyMetaData(QName name) {
370356
PropertyMetaData metadata = super.getPropertyMetaData(name);
371357

372-
if (!_allAttributes) {
358+
if (!_factory.isSpaceManaged(_path)) {
373359
return metadata;
374360
}
375361

376362
// Milton accepts null and PropertyMetaData.UNKNOWN to mean the
377363
// property is unknown.
378364
if ((metadata == null || metadata.isUnknown()) && QUOTA_PROPERTIES.contains(name)) {
379-
var maybeToken = getWriteToken();
380-
if (_factory.isSpaceManaged(maybeToken)) {
381-
return READONLY_LONG;
382-
}
365+
metadata = READONLY_LONG;
383366
}
384367

385368
return metadata;
@@ -389,12 +372,7 @@ public PropertyMetaData getPropertyMetaData(QName name) {
389372
public List<QName> getAllPropertyNames() {
390373
List<QName> genericNames = super.getAllPropertyNames();
391374

392-
if (!_allAttributes) {
393-
return genericNames;
394-
}
395-
396-
var maybeToken = getWriteToken();
397-
if (!_factory.isSpaceManaged(maybeToken)) {
375+
if (!_factory.isSpaceManaged(_path)) {
398376
return genericNames;
399377
}
400378

modules/dcache-webdav/src/main/java/org/dcache/webdav/DcacheResourceFactory.java

Lines changed: 11 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import static org.dcache.namespace.FileAttribute.PNFSID;
1919
import static org.dcache.namespace.FileAttribute.RETENTION_POLICY;
2020
import static org.dcache.namespace.FileAttribute.SIZE;
21-
import static org.dcache.namespace.FileAttribute.STORAGEINFO;
2221
import static org.dcache.namespace.FileAttribute.TYPE;
2322
import static org.dcache.namespace.FileAttribute.XATTR;
2423
import static org.dcache.namespace.FileType.DIR;
@@ -176,10 +175,6 @@ public class DcacheResourceFactory
176175

177176
public static final String TRANSACTION_ATTRIBUTE = "org.dcache.transaction";
178177

179-
private static final Set<FileAttribute> MINIMALLY_REQUIRED_ATTRIBUTES =
180-
EnumSet.of(TYPE, PNFSID, CREATION_TIME, MODIFICATION_TIME, SIZE,
181-
MODE, OWNER, OWNER_GROUP);
182-
183178
private static final Set<FileAttribute> REQUIRED_ATTRIBUTES =
184179
EnumSet.of(TYPE, PNFSID, CREATION_TIME, MODIFICATION_TIME, SIZE,
185180
MODE, OWNER, OWNER_GROUP, XATTR);
@@ -190,7 +185,7 @@ public class DcacheResourceFactory
190185
// Additional attributes needed for PROPFIND requests; e.g., to supply
191186
// values for properties.
192187
private static final Set<FileAttribute> PROPFIND_ATTRIBUTES = Sets.union(
193-
EnumSet.of(CHECKSUM, ACCESS_LATENCY, RETENTION_POLICY, STORAGEINFO),
188+
EnumSet.of(CHECKSUM, ACCESS_LATENCY, RETENTION_POLICY),
194189
PoolMonitorV5.getRequiredAttributesForFileLocality());
195190

196191
private static final String PROTOCOL_INFO_NAME = "Http";
@@ -205,11 +200,6 @@ public class DcacheResourceFactory
205200
private static final Splitter PATH_SPLITTER =
206201
Splitter.on('/').omitEmptyStrings();
207202

208-
enum PropfindProperties {
209-
PERFORMANCE,
210-
CLIENT_COMPATIBLE
211-
};
212-
213203
private static final PercentEscaper METALINK_NAME_ESCAPER = new PercentEscaper("", false);
214204

215205
// See https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xhtml
@@ -261,7 +251,6 @@ enum PropfindProperties {
261251
private boolean _impatientClientProxied = true;
262252
private boolean _isOverwriteAllowed;
263253
private boolean _isAnonymousListingAllowed;
264-
private boolean _includeAllAttributesForPropfind;
265254

266255
private String _staticContentPath;
267256
private ReloadableTemplate _template;
@@ -633,9 +622,9 @@ public Resource getResource(String host, String requestPath) {
633622
public DcacheResource getResource(FsPath path) {
634623
checkPathAllowed(path);
635624

625+
String requestPath = getRequestPath();
636626
boolean haveRetried = false;
637627
Subject subject = getSubject();
638-
String requestPath = getRequestPath();
639628

640629
try {
641630
while (true) {
@@ -677,8 +666,7 @@ public DcacheResource getResource(FsPath path) {
677666
*/
678667
private DcacheResource getResource(FsPath path, FileAttributes attributes) {
679668
if (attributes.getFileType() == DIR) {
680-
return new DcacheDirectoryResource(this, path, attributes,
681-
isFetchAllAttributes());
669+
return new DcacheDirectoryResource(this, path, attributes);
682670
} else {
683671
return new DcacheFileResource(this, path, attributes);
684672
}
@@ -947,11 +935,6 @@ public void print(FsPath dir, FileAttributes dirAttr, DirectoryEntry entry) {
947935
return result;
948936
}
949937

950-
public void setDefaultPropfindProperties(PropfindProperties defaultPropfindProperties) {
951-
_includeAllAttributesForPropfind =
952-
defaultPropfindProperties == PropfindProperties.CLIENT_COMPATIBLE;
953-
}
954-
955938
private class FileLocalityWrapper {
956939

957940
private final FileLocality _inner;
@@ -1274,8 +1257,7 @@ public void deleteDirectory(PnfsId pnfsid, FsPath path)
12741257
PnfsCreateEntryMessage reply =
12751258
pnfs.createPnfsDirectory(path.toString(), REQUIRED_ATTRIBUTES);
12761259

1277-
return new DcacheDirectoryResource(this, path, reply.getFileAttributes(),
1278-
isFetchAllAttributes());
1260+
return new DcacheDirectoryResource(this, path, reply.getFileAttributes());
12791261
}
12801262

12811263
public void move(FsPath sourcePath, PnfsId pnfsId, FsPath newPath)
@@ -1566,16 +1548,13 @@ private void initializeTransfer(HttpTransfer transfer, Subject subject)
15661548
}
15671549

15681550
private Set<FileAttribute> buildRequestedAttributes() {
1569-
boolean all = isFetchAllAttributes();
1570-
1571-
Set<FileAttribute> attributes = all ? EnumSet.copyOf(REQUIRED_ATTRIBUTES) :
1572-
EnumSet.copyOf(MINIMALLY_REQUIRED_ATTRIBUTES);
1551+
Set<FileAttribute> attributes = EnumSet.copyOf(REQUIRED_ATTRIBUTES);
15731552

15741553
if (isDigestRequested()) {
15751554
attributes.add(CHECKSUM);
15761555
}
15771556

1578-
if (isPropfindRequest() && all) {
1557+
if (isPropfindRequest()) {
15791558
// FIXME: Unfortunately, Milton parses the request body after
15801559
// requesting the Resource, so we cannot know which additional
15811560
// attributes are being requested; therefore, we must request all
@@ -1586,14 +1565,6 @@ private Set<FileAttribute> buildRequestedAttributes() {
15861565
return attributes;
15871566
}
15881567

1589-
private boolean isFetchAllAttributes() {
1590-
if (!isPropfindRequest()) {
1591-
return true;
1592-
}
1593-
1594-
return _includeAllAttributesForPropfind;
1595-
}
1596-
15971568
/**
15981569
* Return the RFC 3230 Want-Digest header value, if present. If multiple headers are present
15991570
* then return a single value obtained by taking the values and creating the equivalent
@@ -1651,7 +1622,7 @@ private Optional<Space> lookupSpaceById(String id) {
16511622
}
16521623
}
16531624

1654-
public Optional<String> lookupWriteToken(FsPath path) {
1625+
private Optional<String> lookupWriteToken(FsPath path) {
16551626
try {
16561627
return _writeTokenCache.get(path);
16571628
} catch (ExecutionException e) {
@@ -1662,14 +1633,14 @@ public Optional<String> lookupWriteToken(FsPath path) {
16621633
}
16631634
}
16641635

1665-
public Space spaceForToken(Optional<String> maybeToken) throws SpaceException {
1666-
return maybeToken
1636+
public Space spaceForPath(FsPath path) throws SpaceException {
1637+
return lookupWriteToken(path)
16671638
.flatMap(this::lookupSpaceById)
16681639
.orElseThrow(() -> new SpaceException("Path not under space management"));
16691640
}
16701641

1671-
public boolean isSpaceManaged(Optional<String> maybeToken) {
1672-
return maybeToken
1642+
public boolean isSpaceManaged(FsPath path) {
1643+
return lookupWriteToken(path)
16731644
.flatMap(this::lookupSpaceById)
16741645
.isPresent();
16751646
}

modules/dcache-webdav/src/main/resources/org/dcache/webdav/webdav.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,6 @@
230230
<property name="overwriteAllowed" value="${webdav.enable.overwrite}"/>
231231
<property name="redirectToHttps" value="${webdav.redirect.allow-https}"/>
232232
<property name="poolMonitor" ref="pool-monitor"/>
233-
<property name="defaultPropfindProperties" value="${webdav.default-propfind-properties}"/>
234233
</bean>
235234

236235
<bean id="pool-manager-handler" class="org.dcache.poolmanager.PoolManagerHandlerSubscriber">

modules/dcache/src/main/java/org/dcache/space/ReservationCaches.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,6 @@ public void failure(int rc, Object error) {
251251
});
252252
}
253253

254-
public static java.util.Optional<String> writeToken(FileAttributes attr) {
255-
StorageInfo info = attr.getStorageInfo();
256-
return java.util.Optional.ofNullable(info.getMap().get("writeToken"));
257-
}
258-
259254
/**
260255
* Cache queries to discover if a directory has the "WriteToken" tag set.
261256
*/
@@ -267,6 +262,11 @@ public static LoadingCache<FsPath, java.util.Optional<String>> buildWriteTokenLo
267262
.refreshAfterWrite(5, MINUTES)
268263
.recordStats()
269264
.build(new CacheLoader<FsPath, java.util.Optional<String>>() {
265+
private java.util.Optional<String> writeToken(FileAttributes attr) {
266+
StorageInfo info = attr.getStorageInfo();
267+
return java.util.Optional.ofNullable(info.getMap().get("writeToken"));
268+
}
269+
270270
@Override
271271
public java.util.Optional<String> load(FsPath path)
272272
throws CacheException, NoRouteToCellException, InterruptedException {

skel/share/defaults/webdav.properties

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,8 @@ webdav.allowed.client.origins =
763763
#
764764
(one-of?true|false)webdav.redirect.allow-https=true
765765

766+
767+
766768
# ---- Kafka service enabled
767769
#
768770
(one-of?true|false|${dcache.enable.kafka})webdav.enable.kafka = ${dcache.enable.kafka}
@@ -775,35 +777,4 @@ webdav.kafka.topic = ${dcache.kafka.topic}
775777
webdav.kafka.producer.bootstrap.servers = ${dcache.kafka.bootstrap-servers}
776778

777779

778-
(prefix)webdav.kafka.producer.configs = Configuration for Kafka Producer
779-
780-
# --- Default PROPFIND properties
781-
#
782-
# The PROPFIND request allows a client to discover information
783-
# (properties) of dCache content. When making a PROPFIND request,
784-
# the client normally indicates which properties are of interest. If
785-
# not specified then the WebDAV server (dCache) is free to return a
786-
# default set of information.
787-
#
788-
# Certain clients make PROPFIND requests without specifying
789-
# the desired set of properties, triggering a default set of
790-
# properties. There are two problems with this: first, the
791-
# clients may react badly if information is missing from this default;
792-
# second, some of the required properties may have an adverse
793-
# performance impact for dCache.
794-
#
795-
# This property controls whether to support client-side requests for
796-
# properties beyond a minimal set or not.
797-
#
798-
# PERFORMANCE -- always return only a minimal set of information that does
799-
# not incur any additional overhead. (These are basically
800-
# the same as what a POSIX list request would proviode).
801-
#
802-
# CLIENT_COMPATIBLE -- return the set of information required by
803-
# the clients. If the client does not specify the properties,
804-
# it will get a maximal default set.
805-
#
806-
# Because the performance impact of the latter under the most common usage scenarios
807-
# could be considerable, the default is set to PERFORMANCE.
808-
#
809-
(one-of?PERFORMANCE|CLIENT_COMPATIBLE)webdav.default-propfind-properties = PERFORMANCE
780+
(prefix)webdav.kafka.producer.configs = Configuration for Kafka Producer

0 commit comments

Comments
 (0)