K0K0V0K commented on code in PR #8881:
URL: https://github.com/apache/hadoop/pull/8881#discussion_r4409499141
##########
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/CommonConfigurationKeysPublic.java:
##########
@@ -1114,5 +1103,65 @@ public class CommonConfigurationKeysPublic {
*/
public static final String JMX_NAN_FILTER =
"hadoop.http.jmx.nan-filter.enabled";
public static final boolean JMX_NAN_FILTER_DEFAULT = false;
+
+ /**
+ * Idle timeout after which an MCP session is evicted.
+ * @see
+ * <a
href="{@docRoot}/../hadoop-project-dist/hadoop-common/core-default.xml">
+ * core-default.xml</a>
+ */
+ public static final String HADOOP_MCP_SESSION_TIMEOUT_MS_KEY =
+ "hadoop.mcp.session.timeout.ms";
+ public static final long HADOOP_MCP_SESSION_TIMEOUT_MS_DEFAULT = 30 * 60 *
1000L;
+
+ /**
+ * Maximum number of concurrent MCP sessions.
+ * @see
+ * <a
href="{@docRoot}/../hadoop-project-dist/hadoop-common/core-default.xml">
+ * core-default.xml</a>
+ */
+ public static final String HADOOP_MCP_SESSION_MAX_KEY =
"hadoop.mcp.session.max";
+ public static final int HADOOP_MCP_SESSION_MAX_DEFAULT = 1000;
+
+ /**
+ * Maximum number of MCP tool calls per session within one rate-limit
window; 0 or less
+ * disables the limit.
+ * @see
+ * <a
href="{@docRoot}/../hadoop-project-dist/hadoop-common/core-default.xml">
+ * core-default.xml</a>
+ */
+ public static final String HADOOP_MCP_SESSION_TOOL_CALL_LIMIT_KEY =
+ "hadoop.mcp.session.tool-call.limit";
+ public static final int HADOOP_MCP_SESSION_TOOL_CALL_LIMIT_DEFAULT = 600;
+
+ /**
+ * Length of the MCP tool-call rate-limit window.
+ * @see
+ * <a
href="{@docRoot}/../hadoop-project-dist/hadoop-common/core-default.xml">
+ * core-default.xml</a>
+ */
+ public static final String HADOOP_MCP_SESSION_TOOL_CALL_WINDOW_MS_KEY =
+ "hadoop.mcp.session.tool-call.window.ms";
+ public static final long HADOOP_MCP_SESSION_TOOL_CALL_WINDOW_MS_DEFAULT = 60
* 1000L;
+
+ /**
+ * Maximum total length of the text one MCP tool call may return in
characters.
+ * @see
+ * <a
href="{@docRoot}/../hadoop-project-dist/hadoop-common/core-default.xml">
+ * core-default.xml</a>
+ */
+ public static final String HADOOP_MCP_TOOL_CALL_MAX_OUTPUT_CHARS_KEY =
+ "hadoop.mcp.tool-call.max-output-chars";
+ public static final int HADOOP_MCP_TOOL_CALL_MAX_OUTPUT_CHARS_DEFAULT = 1024
* 1024;
+
+ /**
+ * Maximum number of request ids an MCP session may use.
Review Comment:
Nit: Maybe worth to mention this is ignored if set to 0
##########
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/mcp/McpSession.java:
##########
@@ -0,0 +1,132 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache 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://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.mcp;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * An MCP session, created by {@code initialize} and identified by the
+ * {@code Mcp-Session-Id} header.
+ *
+ * <p>State changes are package-private, so tool handlers that receive a
session can read it
+ * but cannot change it. Idle time is tracked by {@link McpSessionStore}, not
here.
+ */
[email protected]
[email protected]
+public final class McpSession {
+
+ private final String id;
+ private final String negotiatedProtocolVersion;
+ private final Map<String, Object> clientInfo;
+ private final Map<String, Object> clientCapabilities;
+ private final long creationTimeMs;
+ private final AtomicReference<McpSessionState> state =
+ new AtomicReference<>(McpSessionState.INITIALIZING);
+ private final McpRateLimiter mcpRateLimiter;
+ private final int maxRequestIds;
+ private final Set<String> usedRequestIds = new HashSet<>();
+
+ /**
+ * @param maxRequestIds number of request ids the session may use; 0 or less
is unlimited
+ */
+ McpSession(String id, String negotiatedProtocolVersion, Map<String, Object>
clientInfo,
+ Map<String, Object> clientCapabilities, long creationTimeMs,
+ McpRateLimiter mcpRateLimiter, int maxRequestIds) {
+ this.id = id;
+ this.negotiatedProtocolVersion = negotiatedProtocolVersion;
+ this.clientInfo = clientInfo;
+ this.clientCapabilities = clientCapabilities;
+ this.creationTimeMs = creationTimeMs;
+ this.mcpRateLimiter = mcpRateLimiter;
+ this.maxRequestIds = maxRequestIds;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getNegotiatedProtocolVersion() {
+ return negotiatedProtocolVersion;
+ }
+
+ /** @return the {@code clientInfo} sent with {@code initialize}; never null
*/
+ public Map<String, Object> getClientInfo() {
+ return clientInfo;
+ }
+
+ /** @return the client {@code capabilities} sent with {@code initialize};
never null */
+ public Map<String, Object> getClientCapabilities() {
+ return clientCapabilities;
+ }
+
+ /** @return wall-clock creation time, in milliseconds since the epoch */
+ public long getCreationTimeMs() {
+ return creationTimeMs;
+ }
+
+ public McpSessionState getState() {
+ return state.get();
+ }
+
+ /**
+ * Moves the session from {@link McpSessionState#INITIALIZING} to
+ * {@link McpSessionState#READY}.
+ *
+ * @return true if the state changed; false if the session was already ready
+ */
+ boolean markReady() {
+ return state.compareAndSet(McpSessionState.INITIALIZING,
McpSessionState.READY);
+ }
+
+ McpRateLimiter getMcpRateLimiter() {
+ return mcpRateLimiter;
+ }
+
+ /**
+ * Records a request id, which the specification forbids reusing within a
session.
+ * {@code 1} and {@code "1"} are different ids.
+ *
+ * @throws RequestRejectedException with 404 if the session has used its
maximum number of
+ * ids, which ends the session; with 400 if the id was already used in
this session
+ */
+ synchronized void recordRequestId(JsonNode idNode) throws
RequestRejectedException {
Review Comment:
Correct me if i am wrong, but when a session hits
hadoop.mcp.session.max-request-ids, recordRequestId returns HTTP 404 but the
session remains in McpSessionStore. So exhausted sessions can hold a
concurrent-session slot and block new initialize until restart or manual DELETE.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]