You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by GitBox <gi...@apache.org> on 2021/05/04 16:06:32 UTC

[GitHub] [maven-resolver] gnodet opened a new pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

gnodet opened a new pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105


   First draft of a simple inter-process SyncContext, not using the `NamedLock` api because the api is too fined grained and it would lead to multiple inter-process calls, while a single call could be sufficient. 


-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] gnodet commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
gnodet commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626020017



##########
File path: maven-resolver-synccontext-simple/pom.xml
##########
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.resolver</groupId>
+    <artifactId>maven-resolver</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-resolver-named-locks-simple</artifactId>

Review comment:
       What about `maven-resolver-synccontext-ipc` then ?




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] gnodet commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
gnodet commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626031798



##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SimpleSyncContextFactory.java
##########
@@ -0,0 +1,368 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SyncContext;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.synccontext.SyncContextFactory;
+
+@Named
+@Singleton
+public class SimpleSyncContextFactory implements SyncContextFactory {
+
+    public static final String REQUEST_CONTEXT = "request-context";
+    public static final String REQUEST_ACQUIRE = "request-acquire";
+    public static final String REQUEST_CLOSE = "request-close";
+    public static final String RESPONSE_CONTEXT = "response-context";
+    public static final String RESPONSE_ACQUIRE = "response-acquire";
+    public static final String RESPONSE_CLOSE = "response-close";
+
+    Socket socket;
+    DataOutputStream output;
+    DataInputStream input;
+    Thread receiver;
+    AtomicInteger requestId = new AtomicInteger();
+    Map<Integer, CompletableFuture<List<String>>> responses = new ConcurrentHashMap<>();
+
+    @Override
+    public SyncContext newInstance(RepositorySystemSession session, boolean shared) {
+        return new SimpleSyncContext(session, shared);
+    }
+
+    synchronized Socket ensureInitialized() throws IOException {
+        if (socket == null) {
+            socket = createClient();
+            input = new DataInputStream(socket.getInputStream());
+            output = new DataOutputStream(socket.getOutputStream());
+            receiver = new Thread(this::receive);
+            receiver.setDaemon(true);
+            receiver.start();
+        }
+        return socket;
+    }
+
+    synchronized Socket createClient() throws IOException {
+        Path registryFile = Paths.get(System.getProperty("user.home"))
+                .resolve(".m2/sync.bin").toAbsolutePath().normalize();

Review comment:
       What about using a file at the root of the local repository by default ? It should be available when the sync context is created using `session.getLocalRepository().getBasedir()`.




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] gnodet commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
gnodet commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626020989



##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SimpleSyncContextFactory.java
##########
@@ -0,0 +1,368 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SyncContext;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.synccontext.SyncContextFactory;
+
+@Named
+@Singleton
+public class SimpleSyncContextFactory implements SyncContextFactory {
+
+    public static final String REQUEST_CONTEXT = "request-context";
+    public static final String REQUEST_ACQUIRE = "request-acquire";
+    public static final String REQUEST_CLOSE = "request-close";
+    public static final String RESPONSE_CONTEXT = "response-context";
+    public static final String RESPONSE_ACQUIRE = "response-acquire";
+    public static final String RESPONSE_CLOSE = "response-close";
+
+    Socket socket;
+    DataOutputStream output;
+    DataInputStream input;
+    Thread receiver;
+    AtomicInteger requestId = new AtomicInteger();
+    Map<Integer, CompletableFuture<List<String>>> responses = new ConcurrentHashMap<>();
+
+    @Override
+    public SyncContext newInstance(RepositorySystemSession session, boolean shared) {
+        return new SimpleSyncContext(session, shared);
+    }
+
+    synchronized Socket ensureInitialized() throws IOException {
+        if (socket == null) {
+            socket = createClient();
+            input = new DataInputStream(socket.getInputStream());
+            output = new DataOutputStream(socket.getOutputStream());
+            receiver = new Thread(this::receive);
+            receiver.setDaemon(true);
+            receiver.start();
+        }
+        return socket;
+    }
+
+    synchronized Socket createClient() throws IOException {
+        Path registryFile = Paths.get(System.getProperty("user.home"))
+                .resolve(".m2/sync.bin").toAbsolutePath().normalize();

Review comment:
       Fair enough.




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] gnodet commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
gnodet commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626029298



##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SimpleSyncContextFactory.java
##########
@@ -0,0 +1,368 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SyncContext;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.synccontext.SyncContextFactory;
+
+@Named
+@Singleton
+public class SimpleSyncContextFactory implements SyncContextFactory {
+
+    public static final String REQUEST_CONTEXT = "request-context";
+    public static final String REQUEST_ACQUIRE = "request-acquire";
+    public static final String REQUEST_CLOSE = "request-close";
+    public static final String RESPONSE_CONTEXT = "response-context";
+    public static final String RESPONSE_ACQUIRE = "response-acquire";
+    public static final String RESPONSE_CLOSE = "response-close";
+
+    Socket socket;
+    DataOutputStream output;
+    DataInputStream input;
+    Thread receiver;
+    AtomicInteger requestId = new AtomicInteger();
+    Map<Integer, CompletableFuture<List<String>>> responses = new ConcurrentHashMap<>();
+
+    @Override
+    public SyncContext newInstance(RepositorySystemSession session, boolean shared) {
+        return new SimpleSyncContext(session, shared);
+    }
+
+    synchronized Socket ensureInitialized() throws IOException {
+        if (socket == null) {
+            socket = createClient();
+            input = new DataInputStream(socket.getInputStream());
+            output = new DataOutputStream(socket.getOutputStream());
+            receiver = new Thread(this::receive);
+            receiver.setDaemon(true);
+            receiver.start();
+        }
+        return socket;
+    }
+
+    synchronized Socket createClient() throws IOException {
+        Path registryFile = Paths.get(System.getProperty("user.home"))
+                .resolve(".m2/sync.bin").toAbsolutePath().normalize();
+        if (!Files.isRegularFile(registryFile)) {
+            if (!Files.isDirectory(registryFile.getParent())) {
+                Files.createDirectories(registryFile.getParent());
+            }
+        }
+
+        try (RandomAccessFile raf = new RandomAccessFile(registryFile.toFile(), "rw")) {

Review comment:
       The locking part is quite important to ensure proper behavior.  I think the lock file could be made configurable.  I'll add a configuration property `aether.syncContext.simple.lockFile` so that we can point to a non NFS.  I can also fail fast during in the constructor to try and lock that file.




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] gnodet commented on pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
gnodet commented on pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#issuecomment-908924664


   The latest code is available at https://github.com/mvndaemon/mvnd/tree/master/sync/src/main/java/org/mvndaemon/mvnd/sync


-- 
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: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] gnodet closed pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
gnodet closed pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105


   


-- 
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: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] michael-o commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
michael-o commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626001470



##########
File path: maven-resolver-synccontext-simple/pom.xml
##########
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.resolver</groupId>
+    <artifactId>maven-resolver</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-resolver-named-locks-simple</artifactId>

Review comment:
       Personally, I don't consider IPC to be simple. It can be brittle.

##########
File path: maven-resolver-synccontext-simple/pom.xml
##########
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.resolver</groupId>
+    <artifactId>maven-resolver</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-resolver-named-locks-simple</artifactId>

Review comment:
       This isn't a named lock. Why did you name it like that?

##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SyncServer.java
##########
@@ -0,0 +1,352 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import sun.misc.Signal;
+import sun.misc.SignalHandler;
+
+public class SyncServer {
+
+    private ServerSocket serverSocket;
+    private volatile long lastUsed;
+    private boolean closing;
+    private AtomicInteger counter = new AtomicInteger();
+
+    private Map<String, Repo> repos = new ConcurrentHashMap<>();
+    private Map<String, Context> contexts = new ConcurrentHashMap<>();
+
+    public static void main(String[] args) throws Exception {
+        // When spawning a new process, the child process is create within
+        // the same process group.  This means that a few signals are sent
+        // to the whole group.  This is the case for SIGINT (Ctrl-C) and
+        // SIGTSTP (Ctrl-Z) which are both sent to all the processed in the
+        // group when initiated from the controlling terminal.
+        // This is only a problem when the client creates the daemon, but
+        // without ignoring those signals, a client being interrupted will
+        // also interrupt and kill the daemon.
+        try {
+            Signal.handle(new Signal("INT"), SignalHandler.SIG_IGN);
+            if (System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("win")) {
+                Signal.handle(new Signal("TSTP"), SignalHandler.SIG_IGN);
+            }
+        } catch (Throwable t) {
+            System.err.println("Unable to ignore INT and TSTP signals");
+            t.printStackTrace();
+        }
+
+        int tmpPort = Integer.parseInt(args[0]);
+        long rand = Long.parseLong(args[1]);
+
+        SyncServer server = new SyncServer();
+        new Thread(server::run).start();
+        int port = server.getPort();
+
+        try (Socket s = new Socket()) {
+            s.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), tmpPort));
+            try (DataOutputStream dos = new DataOutputStream(s.getOutputStream())) {
+                dos.writeLong(rand);
+                dos.writeLong(getPid());
+                dos.writeInt(port);
+                dos.flush();
+            }
+        }
+    }
+
+    private static long getPid() {
+        try {
+            return ProcessHandle.current().pid();
+        } catch (Throwable t) {
+            RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
+            String jvmName = bean.getName();
+            return Long.valueOf(jvmName.split("@")[0]);
+        }
+    }
+
+    public SyncServer() throws IOException {
+        serverSocket = new ServerSocket();
+        serverSocket.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
+    }
+
+    public int getPort() {
+        return serverSocket.getLocalPort();
+    }
+
+    public void run() {
+        try {
+            System.out.println("SyncServer started");
+            use();
+            run(this::expirationCheck);
+            while (true) {
+                Socket socket = this.serverSocket.accept();
+                run(() -> client(socket));
+            }
+        } catch (Throwable t) {
+            if (!closing) {
+                System.err.println("Error running sync server loop");
+                t.printStackTrace();
+            }
+        }
+    }
+
+    private void run(Runnable runnable) {
+        Thread thread = new Thread(runnable);
+        thread.setDaemon(true);
+        thread.start();
+    }
+
+    private void client(Socket socket) {
+        System.out.println("Client connected");
+        use();
+        Map<String, Context> clientContexts = new ConcurrentHashMap<>();
+        try {
+            DataInputStream input = new DataInputStream(socket.getInputStream());
+            DataOutputStream output = new DataOutputStream(socket.getOutputStream());
+            while (true) {
+                int requestId = input.readInt();
+                int sz = input.readInt();
+                List<String> request = new ArrayList<>(sz);
+                for (int i = 0; i < sz; i++) {
+                    request.add(input.readUTF());
+                }
+                if (request.isEmpty()) {
+                    throw new IOException("Received invalid request");
+                }
+                switch (request.get(0)) {
+                case SimpleSyncContextFactory.REQUEST_CONTEXT: {
+                    if (request.size() < 3) {
+                        return;
+                    }
+                    String repo = request.get(1);
+                    boolean shared = Boolean.parseBoolean(request.get(2));
+                    Context context = newContext(repo, shared);
+                    contexts.put(context.id, context);
+                    clientContexts.put(context.id, context);
+                    synchronized (output) {
+                        output.writeInt(requestId);
+                        output.writeInt(2);
+                        output.writeUTF(SimpleSyncContextFactory.RESPONSE_CONTEXT);
+                        output.writeUTF(context.id);
+                        output.flush();
+                    }
+                    break;
+                }
+                case SimpleSyncContextFactory.REQUEST_ACQUIRE: {
+                    String contextId = request.get(1);
+                    Context context = contexts.get(contextId);
+                    if (context == null) {
+                        return;
+                    }
+                    List<String> keys = request.subList(2, request.size());
+                    context.lock(keys).thenRun(() -> {
+                        try {
+                            synchronized (output) {
+                                output.writeInt(requestId);
+                                output.writeInt(1);
+                                output.writeUTF(SimpleSyncContextFactory.RESPONSE_ACQUIRE);
+                                output.flush();
+                            }
+                        } catch (IOException e) {
+                            try {
+                                socket.close();
+                            } catch (IOException ioException) {
+                                // ignore
+                            }
+                        }
+                    });
+                    break;
+                }
+                case SimpleSyncContextFactory.REQUEST_CLOSE: {
+                    String contextId = request.get(1);
+                    Context context = contexts.remove(contextId);
+                    clientContexts.remove(contextId);
+                    if (context == null) {
+                        return;
+                    }
+                    context.unlock();
+                    synchronized (output) {
+                        output.writeInt(requestId);
+                        output.writeInt(1);
+                        output.writeUTF(SimpleSyncContextFactory.RESPONSE_CLOSE);
+                        output.flush();
+                    }
+                    break;
+                }
+                }
+            }
+        } catch (Throwable t) {
+            System.err.println("Error reading request");
+            t.printStackTrace();
+        } finally {
+            clientContexts.values().forEach(Context::unlock);
+        }
+    }
+
+    public Context newContext(String repo, boolean shared) {
+        String contextId = String.format("%08x", counter.incrementAndGet());
+        return new Context(repos.computeIfAbsent(repo, Repo::new), contextId, shared);
+    }
+
+    static class Waiter {
+        final Context context;
+        final CompletableFuture<Void> future;
+
+        public Waiter(Context context, CompletableFuture<Void> future) {
+            this.context = context;
+            this.future = future;
+        }
+    }
+
+    static class Lock {
+
+        final String key;
+
+        List<Context> holders;
+        List<Waiter> waiters;
+
+        public Lock(String key) {
+            this.key = key;
+        }
+
+        public synchronized CompletableFuture<Void> lock(Context context) {
+            if (holders == null) {
+                holders = new ArrayList<>();
+            }
+            if (holders.isEmpty() || holders.get(0).shared && context.shared) {
+                holders.add(context);
+                return CompletableFuture.completedFuture(null);
+            }
+            if (waiters == null) {
+                waiters = new ArrayList<>();
+            }
+
+            CompletableFuture<Void> future = new CompletableFuture<>();
+            waiters.add(new Waiter(context, future));
+            return future;
+        }
+
+        public synchronized void unlock(Context context) {
+            if (holders.remove(context)) {
+                while (waiters != null && !waiters.isEmpty()
+                        && (holders.isEmpty() || holders.get(0).shared && waiters.get(0).context.shared)) {
+                    Waiter waiter = waiters.remove(0);
+                    holders.add(waiter.context);
+                    waiter.future.complete(null);
+                }
+            } else if (waiters != null) {
+                for (Iterator<Waiter> it = waiters.iterator(); it.hasNext();) {
+                    Waiter waiter = it.next();
+                    if (waiter.context == context) {
+                        it.remove();
+                        waiter.future.cancel(false);
+                    }
+                }
+            }
+        }
+
+    }
+
+    static class Repo {
+
+        final String repository;
+        final Map<String, Lock> locks = new ConcurrentHashMap<>();
+
+        public Repo(String repository) {
+            this.repository = repository;
+        }
+
+        public CompletableFuture<?> lock(Context context, List<String> keys) {
+            CompletableFuture<?>[] futures = keys.stream()
+                    .map(k -> locks.computeIfAbsent(k, Lock::new))
+                    .map(l -> l.lock(context))
+                    .toArray(CompletableFuture[]::new);
+            return CompletableFuture.allOf(futures);
+        }
+
+        public void unlock(Context context, List<String> keys) {
+            keys.stream()
+                    .map(k -> locks.computeIfAbsent(k, Lock::new))
+                    .forEach(l -> l.unlock(context));
+        }
+
+    }
+
+    static class Context {
+
+        final Repo repo;
+        final String id;
+        final boolean shared;
+        final List<String> locks = new CopyOnWriteArrayList<>();
+
+        public Context(Repo repo, String contextId, boolean shared) {
+            this.repo = repo;
+            this.id = contextId;
+            this.shared = shared;
+        }
+
+        public CompletableFuture<?> lock(List<String> keys) {
+            locks.addAll(keys);
+            return repo.lock(this, keys);
+        }
+
+        public void unlock() {
+            repo.unlock(this, locks);
+        }
+    }
+
+    private void use() {
+        lastUsed = System.currentTimeMillis();

Review comment:
       Use nanoTime for elapsed time instead of wall clock.

##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SimpleSyncContextFactory.java
##########
@@ -0,0 +1,368 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SyncContext;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.synccontext.SyncContextFactory;
+
+@Named
+@Singleton
+public class SimpleSyncContextFactory implements SyncContextFactory {
+
+    public static final String REQUEST_CONTEXT = "request-context";
+    public static final String REQUEST_ACQUIRE = "request-acquire";
+    public static final String REQUEST_CLOSE = "request-close";
+    public static final String RESPONSE_CONTEXT = "response-context";
+    public static final String RESPONSE_ACQUIRE = "response-acquire";
+    public static final String RESPONSE_CLOSE = "response-close";
+
+    Socket socket;
+    DataOutputStream output;
+    DataInputStream input;
+    Thread receiver;
+    AtomicInteger requestId = new AtomicInteger();
+    Map<Integer, CompletableFuture<List<String>>> responses = new ConcurrentHashMap<>();
+
+    @Override
+    public SyncContext newInstance(RepositorySystemSession session, boolean shared) {
+        return new SimpleSyncContext(session, shared);
+    }
+
+    synchronized Socket ensureInitialized() throws IOException {
+        if (socket == null) {
+            socket = createClient();
+            input = new DataInputStream(socket.getInputStream());
+            output = new DataOutputStream(socket.getOutputStream());
+            receiver = new Thread(this::receive);
+            receiver.setDaemon(true);
+            receiver.start();
+        }
+        return socket;
+    }
+
+    synchronized Socket createClient() throws IOException {
+        Path registryFile = Paths.get(System.getProperty("user.home"))
+                .resolve(".m2/sync.bin").toAbsolutePath().normalize();
+        if (!Files.isRegularFile(registryFile)) {
+            if (!Files.isDirectory(registryFile.getParent())) {
+                Files.createDirectories(registryFile.getParent());
+            }
+        }
+
+        try (RandomAccessFile raf = new RandomAccessFile(registryFile.toFile(), "rw")) {

Review comment:
       Will fail when user home is on NFS.

##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SimpleSyncContextFactory.java
##########
@@ -0,0 +1,368 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SyncContext;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.synccontext.SyncContextFactory;
+
+@Named
+@Singleton
+public class SimpleSyncContextFactory implements SyncContextFactory {

Review comment:
       This interferes now with the `DefaultSyncContextFactory` with the same priority. You have have a different priority to shadow the default one when one drops this JAR to ext classpath.

##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SimpleSyncContextFactory.java
##########
@@ -0,0 +1,368 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SyncContext;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.synccontext.SyncContextFactory;
+
+@Named
+@Singleton
+public class SimpleSyncContextFactory implements SyncContextFactory {
+
+    public static final String REQUEST_CONTEXT = "request-context";
+    public static final String REQUEST_ACQUIRE = "request-acquire";
+    public static final String REQUEST_CLOSE = "request-close";
+    public static final String RESPONSE_CONTEXT = "response-context";
+    public static final String RESPONSE_ACQUIRE = "response-acquire";
+    public static final String RESPONSE_CLOSE = "response-close";
+
+    Socket socket;
+    DataOutputStream output;
+    DataInputStream input;
+    Thread receiver;
+    AtomicInteger requestId = new AtomicInteger();
+    Map<Integer, CompletableFuture<List<String>>> responses = new ConcurrentHashMap<>();
+
+    @Override
+    public SyncContext newInstance(RepositorySystemSession session, boolean shared) {
+        return new SimpleSyncContext(session, shared);
+    }
+
+    synchronized Socket ensureInitialized() throws IOException {
+        if (socket == null) {
+            socket = createClient();
+            input = new DataInputStream(socket.getInputStream());
+            output = new DataOutputStream(socket.getOutputStream());
+            receiver = new Thread(this::receive);
+            receiver.setDaemon(true);
+            receiver.start();
+        }
+        return socket;
+    }
+
+    synchronized Socket createClient() throws IOException {
+        Path registryFile = Paths.get(System.getProperty("user.home"))
+                .resolve(".m2/sync.bin").toAbsolutePath().normalize();

Review comment:
       No, Maven Resolver is not Maven. You should use a registry file *outside* of Maven's user dir.

##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SimpleSyncContextFactory.java
##########
@@ -0,0 +1,368 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SyncContext;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.synccontext.SyncContextFactory;
+
+@Named
+@Singleton
+public class SimpleSyncContextFactory implements SyncContextFactory {
+
+    public static final String REQUEST_CONTEXT = "request-context";
+    public static final String REQUEST_ACQUIRE = "request-acquire";
+    public static final String REQUEST_CLOSE = "request-close";
+    public static final String RESPONSE_CONTEXT = "response-context";
+    public static final String RESPONSE_ACQUIRE = "response-acquire";
+    public static final String RESPONSE_CLOSE = "response-close";
+
+    Socket socket;
+    DataOutputStream output;
+    DataInputStream input;
+    Thread receiver;
+    AtomicInteger requestId = new AtomicInteger();
+    Map<Integer, CompletableFuture<List<String>>> responses = new ConcurrentHashMap<>();
+
+    @Override
+    public SyncContext newInstance(RepositorySystemSession session, boolean shared) {
+        return new SimpleSyncContext(session, shared);
+    }
+
+    synchronized Socket ensureInitialized() throws IOException {
+        if (socket == null) {
+            socket = createClient();
+            input = new DataInputStream(socket.getInputStream());
+            output = new DataOutputStream(socket.getOutputStream());
+            receiver = new Thread(this::receive);
+            receiver.setDaemon(true);
+            receiver.start();
+        }
+        return socket;
+    }
+
+    synchronized Socket createClient() throws IOException {
+        Path registryFile = Paths.get(System.getProperty("user.home"))
+                .resolve(".m2/sync.bin").toAbsolutePath().normalize();
+        if (!Files.isRegularFile(registryFile)) {
+            if (!Files.isDirectory(registryFile.getParent())) {
+                Files.createDirectories(registryFile.getParent());
+            }
+        }
+
+        try (RandomAccessFile raf = new RandomAccessFile(registryFile.toFile(), "rw")) {
+            InetAddress loopback = InetAddress.getLoopbackAddress();
+            try (FileLock lock = raf.getChannel().lock()) {
+                long pid = 0;
+                int port = 0;
+                try {
+                    pid = raf.readLong();
+                    port = raf.readInt();
+                } catch (EOFException e) {
+                    // ignore
+                }
+                if (port > 0 && pid > 0) {
+                    try {
+                        Socket socket = new Socket();
+                        socket.connect(new InetSocketAddress(loopback, port));
+                        return socket;
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                    try {
+                        ProcessHandle.of(pid).map(ProcessHandle::destroyForcibly);

Review comment:
       This is Java 9+, but we don't have it here.




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] gnodet commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
gnodet commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626011356



##########
File path: maven-resolver-synccontext-simple/pom.xml
##########
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.resolver</groupId>
+    <artifactId>maven-resolver</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-resolver-named-locks-simple</artifactId>

Review comment:
       Yes, I'm quite open to a different name.  It looks simpler to me because it requires zero setup.




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] gnodet commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
gnodet commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626010859



##########
File path: maven-resolver-synccontext-simple/pom.xml
##########
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.resolver</groupId>
+    <artifactId>maven-resolver</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-resolver-named-locks-simple</artifactId>

Review comment:
       An error, I tried to first implement a named lock, but changed and forgot that line.  I'll fix it.




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] michael-o commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
michael-o commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626038252



##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SimpleSyncContextFactory.java
##########
@@ -0,0 +1,368 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SyncContext;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.synccontext.SyncContextFactory;
+
+@Named
+@Singleton
+public class SimpleSyncContextFactory implements SyncContextFactory {
+
+    public static final String REQUEST_CONTEXT = "request-context";
+    public static final String REQUEST_ACQUIRE = "request-acquire";
+    public static final String REQUEST_CLOSE = "request-close";
+    public static final String RESPONSE_CONTEXT = "response-context";
+    public static final String RESPONSE_ACQUIRE = "response-acquire";
+    public static final String RESPONSE_CLOSE = "response-close";
+
+    Socket socket;
+    DataOutputStream output;
+    DataInputStream input;
+    Thread receiver;
+    AtomicInteger requestId = new AtomicInteger();
+    Map<Integer, CompletableFuture<List<String>>> responses = new ConcurrentHashMap<>();
+
+    @Override
+    public SyncContext newInstance(RepositorySystemSession session, boolean shared) {
+        return new SimpleSyncContext(session, shared);
+    }
+
+    synchronized Socket ensureInitialized() throws IOException {
+        if (socket == null) {
+            socket = createClient();
+            input = new DataInputStream(socket.getInputStream());
+            output = new DataOutputStream(socket.getOutputStream());
+            receiver = new Thread(this::receive);
+            receiver.setDaemon(true);
+            receiver.start();
+        }
+        return socket;
+    }
+
+    synchronized Socket createClient() throws IOException {
+        Path registryFile = Paths.get(System.getProperty("user.home"))
+                .resolve(".m2/sync.bin").toAbsolutePath().normalize();
+        if (!Files.isRegularFile(registryFile)) {
+            if (!Files.isDirectory(registryFile.getParent())) {
+                Files.createDirectories(registryFile.getParent());
+            }
+        }
+
+        try (RandomAccessFile raf = new RandomAccessFile(registryFile.toFile(), "rw")) {

Review comment:
       A property is a good idea.




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] gnodet commented on pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
gnodet commented on pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#issuecomment-1030056986


   Dropping as the resolver provides a better option with a file based locking.


-- 
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: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] michael-o commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
michael-o commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626036695



##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SimpleSyncContextFactory.java
##########
@@ -0,0 +1,368 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SyncContext;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.synccontext.SyncContextFactory;
+
+@Named
+@Singleton
+public class SimpleSyncContextFactory implements SyncContextFactory {

Review comment:
       You cannot configure it through properties if you don't use the named approach.




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] gnodet commented on pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
gnodet commented on pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#issuecomment-908924664


   The latest code is available at https://github.com/mvndaemon/mvnd/tree/master/sync/src/main/java/org/mvndaemon/mvnd/sync


-- 
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: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] gnodet commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
gnodet commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626012593



##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SimpleSyncContextFactory.java
##########
@@ -0,0 +1,368 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SyncContext;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.synccontext.SyncContextFactory;
+
+@Named
+@Singleton
+public class SimpleSyncContextFactory implements SyncContextFactory {

Review comment:
       Yes, I removed it to avoid adding a dependency just for that.  I saw that it could be configured through properties, but I agree it should be automatic if added to the classpath.  I'll add it back.




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] michael-o commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
michael-o commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626037936



##########
File path: maven-resolver-synccontext-simple/src/main/java/org/eclipse/aether/named/simple/SimpleSyncContextFactory.java
##########
@@ -0,0 +1,368 @@
+package org.eclipse.aether.named.simple;
+
+/*
+ * 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SyncContext;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.synccontext.SyncContextFactory;
+
+@Named
+@Singleton
+public class SimpleSyncContextFactory implements SyncContextFactory {
+
+    public static final String REQUEST_CONTEXT = "request-context";
+    public static final String REQUEST_ACQUIRE = "request-acquire";
+    public static final String REQUEST_CLOSE = "request-close";
+    public static final String RESPONSE_CONTEXT = "response-context";
+    public static final String RESPONSE_ACQUIRE = "response-acquire";
+    public static final String RESPONSE_CLOSE = "response-close";
+
+    Socket socket;
+    DataOutputStream output;
+    DataInputStream input;
+    Thread receiver;
+    AtomicInteger requestId = new AtomicInteger();
+    Map<Integer, CompletableFuture<List<String>>> responses = new ConcurrentHashMap<>();
+
+    @Override
+    public SyncContext newInstance(RepositorySystemSession session, boolean shared) {
+        return new SimpleSyncContext(session, shared);
+    }
+
+    synchronized Socket ensureInitialized() throws IOException {
+        if (socket == null) {
+            socket = createClient();
+            input = new DataInputStream(socket.getInputStream());
+            output = new DataOutputStream(socket.getOutputStream());
+            receiver = new Thread(this::receive);
+            receiver.setDaemon(true);
+            receiver.start();
+        }
+        return socket;
+    }
+
+    synchronized Socket createClient() throws IOException {
+        Path registryFile = Paths.get(System.getProperty("user.home"))
+                .resolve(".m2/sync.bin").toAbsolutePath().normalize();

Review comment:
       Yes, this sounds reasonable to me, .e.g, `resolver-synccontext-ipc.lock` or similar.




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] michael-o commented on a change in pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
michael-o commented on a change in pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#discussion_r626036452



##########
File path: maven-resolver-synccontext-simple/pom.xml
##########
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.resolver</groupId>
+    <artifactId>maven-resolver</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-resolver-named-locks-simple</artifactId>

Review comment:
       Sounds good.




-- 
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.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [maven-resolver] michael-o commented on pull request #105: [MRESOLVER-178] Introduce a simple inter-process SyncContext

Posted by GitBox <gi...@apache.org>.
michael-o commented on pull request #105:
URL: https://github.com/apache/maven-resolver/pull/105#issuecomment-1002757804


   Do we still need this since it has been removed from mvnd? @cstamas @gnodet 


-- 
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: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org