提交 acad6371 编写于 作者: K Kohsuke Kawaguchi

merged pull request #342

......@@ -217,15 +217,6 @@ public final class WebAppMain implements ServletContextListener {
Jenkins instance = new Hudson(home, context);
context.setAttribute(APP, instance);
// trigger the loading of changelogs in the background,
// but give the system 10 seconds so that the first page
// can be served quickly
Trigger.timer.schedule(new SafeTimerTask() {
public void doRun() {
User.getUnknown().getBuilds();
}
}, 1000*10);
// at this point we are open for business and serving requests normally
LOGGER.info("Jenkins is fully up and running");
success = true;
......
......@@ -24,6 +24,7 @@
package hudson.model;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedSet;
import hudson.AbortException;
import hudson.EnvVars;
import hudson.Functions;
......@@ -71,6 +72,8 @@ import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.StringWriter;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.text.MessageFormat;
import java.util.AbstractSet;
......@@ -284,7 +287,7 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
public FilePath[] getModuleRoots() {
FilePath ws = getWorkspace();
if (ws==null) return null;
return getParent().getScm().getModuleRoots(ws,this);
return getParent().getScm().getModuleRoots(ws, this);
}
/**
......@@ -570,7 +573,7 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
// for historical reasons, null in the scm field means CVS, so we need to explicitly set this to something
// in case check out fails and leaves a broken changelog.xml behind.
// see http://www.nabble.com/CVSChangeLogSet.parse-yields-SAXParseExceptions-when-parsing-bad-*AccuRev*-changelog.xml-files-td22213663.html
AbstractBuild.this.scm = new NullChangeLogParser();
AbstractBuild.this.scm = NullChangeLogParser.INSTANCE;
try {
if (project.checkout(AbstractBuild.this,launcher,listener,new File(getRootDir(),"changelog.xml"))) {
......@@ -631,7 +634,7 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
HashSet<String> r = new HashSet<String>();
for (User u : getCulprits())
r.add(u.getId());
culprits = r;
culprits = ImmutableSortedSet.copyOf(r);
CheckPoint.CULPRITS_DETERMINED.report();
}
}
......@@ -750,6 +753,11 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
return Collections.<Fingerprint>emptyList();
}
/*
* No need to to lock the entire AbstractBuild on change set calculcation
*/
private transient Object changeSetLock = new Object();
/**
* Gets the changes incorporated into this build.
*
......@@ -757,20 +765,22 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
*/
@Exported
public ChangeLogSet<? extends Entry> getChangeSet() {
if (scm==null) {
// for historical reason, null means CVS.
try {
Class<?> c = Jenkins.getInstance().getPluginManager().uberClassLoader.loadClass("hudson.scm.CVSChangeLogParser");
scm = (ChangeLogParser)c.newInstance();
} catch (ClassNotFoundException e) {
// if CVS isn't available, fall back to something non-null.
scm = new NullChangeLogParser();
} catch (InstantiationException e) {
scm = new NullChangeLogParser();
throw (Error)new InstantiationError().initCause(e);
} catch (IllegalAccessException e) {
scm = new NullChangeLogParser();
throw (Error)new IllegalAccessError().initCause(e);
synchronized (changeSetLock) {
if (scm==null) {
// for historical reason, null means CVS.
try {
Class<?> c = Jenkins.getInstance().getPluginManager().uberClassLoader.loadClass("hudson.scm.CVSChangeLogParser");
scm = (ChangeLogParser)c.newInstance();
} catch (ClassNotFoundException e) {
// if CVS isn't available, fall back to something non-null.
scm = NullChangeLogParser.INSTANCE;
} catch (InstantiationException e) {
scm = NullChangeLogParser.INSTANCE;
throw (Error)new InstantiationError().initCause(e);
} catch (IllegalAccessException e) {
scm = NullChangeLogParser.INSTANCE;
throw (Error)new IllegalAccessError().initCause(e);
}
}
}
......
......@@ -119,7 +119,7 @@ public class Hudson extends Jenkins {
* Use {@link #getNodes()}. Since 1.252.
*/
public List<Slave> getSlaves() {
return (List)Collections.unmodifiableList(slaves);
return (List)slaves;
}
/**
......
......@@ -261,6 +261,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
this.project = job;
this.timestamp = timestamp;
this.state = State.NOT_STARTED;
getRootDir().mkdirs();
}
/**
......@@ -848,9 +849,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Files related to this {@link Run} should be stored below this directory.
*/
public File getRootDir() {
File f = new File(project.getBuildDir(),getId());
f.mkdirs();
return f;
return new File(project.getBuildDir(),getId());
}
/**
......
......@@ -386,7 +386,7 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
public RunList getBuilds() {
List<AbstractBuild> r = new ArrayList<AbstractBuild>();
for (AbstractProject<?,?> p : Jenkins.getInstance().getAllItems(AbstractProject.class))
for (AbstractBuild<?,?> b : p.getBuilds())
for (AbstractBuild<?,?> b : p.getBuilds().newBuilds())
if(b.hasParticipant(this))
r.add(b);
return RunList.fromRuns(r);
......
......@@ -34,7 +34,14 @@ import java.io.IOException;
* @author Kohsuke Kawaguchi
*/
public class NullChangeLogParser extends ChangeLogParser {
public static final NullChangeLogParser INSTANCE = new NullChangeLogParser();
public ChangeLogSet<? extends ChangeLogSet.Entry> parse(AbstractBuild build, File changelogFile) throws IOException, SAXException {
return ChangeLogSet.createEmpty(build);
}
public Object readResolve() {
return INSTANCE;
}
}
......@@ -55,7 +55,7 @@ public class NullSCM extends SCM {
}
public ChangeLogParser createChangeLogParser() {
return new NullChangeLogParser();
return NullChangeLogParser.INSTANCE;
}
@Extension
......
......@@ -33,8 +33,11 @@ import hudson.model.Node;
import hudson.util.RobustCollectionConverter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
/**
......@@ -43,22 +46,91 @@ import java.util.concurrent.CopyOnWriteArrayList;
*
* @author Kohsuke Kawaguchi
*/
public final class NodeList extends CopyOnWriteArrayList<Node> {
public final class NodeList extends ArrayList<Node> {
private Map<String,Node> map = new HashMap<String, Node>();
public NodeList() {
}
public NodeList(Collection<? extends Node> c) {
super(c);
for (Node node: c) {
if (map.put(node.getNodeName(), node) != null) {
// make sure that all names are unique
throw new IllegalArgumentException(node.getNodeName()+" is defined more than once");
}
}
}
public NodeList(Node... toCopyIn) {
this(Arrays.asList(toCopyIn));
}
public Node getNode(String nodeName) {
return map.get(nodeName);
}
@Override
public void add(int index, Node element) {
throw new UnsupportedOperationException("unmodifiable list");
}
@Override
public Node remove(int index) {
throw new UnsupportedOperationException("unmodifiable list");
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException("unmodifiable list");
}
@Override
public void clear() {
throw new UnsupportedOperationException("unmodifiable list");
}
@Override
public boolean addAll(Collection<? extends Node> c) {
throw new UnsupportedOperationException("unmodifiable list");
}
@Override
public boolean addAll(int index, Collection<? extends Node> c) {
throw new UnsupportedOperationException("unmodifiable list");
}
@Override
protected void removeRange(int fromIndex, int toIndex) {
throw new UnsupportedOperationException("unmodifiable list");
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException("unmodifiable list");
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException("unmodifiable list");
}
@Override
public boolean add(Node node) {
throw new UnsupportedOperationException("unmodifiable list");
}
public NodeList(Node[] toCopyIn) {
super(toCopyIn);
@Override
public Node set(int index, Node element) {
throw new UnsupportedOperationException("unmodifiable list");
}
/**
* {@link Converter} implementation for XStream.
*
* Serializaion form is compatible with plain {@link List}.
* Serialization form is compatible with plain {@link List}.
*/
public static final class ConverterImpl extends RobustCollectionConverter {
public ConverterImpl(XStream xstream) {
......
......@@ -34,7 +34,6 @@ import hudson.matrix.MatrixConfiguration;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.Build;
import hudson.model.BuildListener;
import hudson.model.DependecyDeclarer;
import hudson.model.DependencyGraph;
......@@ -65,7 +64,6 @@ import java.io.IOException;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
......@@ -294,6 +292,7 @@ public class Fingerprinter extends Recorder implements Serializable, DependecyDe
* Action for displaying fingerprints.
*/
public static final class FingerprintAction implements RunAction {
private final AbstractBuild build;
/**
......
......@@ -23,7 +23,10 @@
*/
package hudson.tasks;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import hudson.model.Action;
import hudson.model.Run;
import hudson.util.xstream.LRUStringConverter;
/**
* Remembers the message ID of the e-mail that was sent for the build.
......@@ -34,9 +37,15 @@ import hudson.model.Action;
* @author Kohsuke Kawaguchi
*/
public class MailMessageIdAction implements Action {
static {
Run.XSTREAM.processAnnotations(MailMessageIdAction.class);
}
/**
* Message ID of the e-mail sent for the build.
*/
@XStreamConverter(LRUStringConverter.class)
public final String messageId;
public MailMessageIdAction(String messageId) {
......
......@@ -193,7 +193,7 @@ public class TestResultAction extends AbstractTestResultAction<TestResultAction>
public Object readResolve() {
super.readResolve(); // let it do the post-deserialization work
if (testData == null) {
testData = new ArrayList<Data>();
testData = new ArrayList<Data>(0);
}
return this;
......
package hudson.util;
import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter;
import com.thoughtworks.xstream.converters.basic.StringConverter;
import org.apache.commons.collections.map.LRUMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class LRUStringConverter extends AbstractSingleValueConverter {
/**
* A Map to store strings as long as needed to map similar strings onto the same instance and conserve memory. The
* map can be set from the outside during construction, so it can be a LRU map or a weak map, synchronised or not.
*/
private final Map<String,String> cache;
public LRUStringConverter() {
this(1000);
}
public LRUStringConverter(int size) {
cache = Collections.synchronizedMap(new LRUMap(size));
}
public boolean canConvert(final Class type) {
return type.equals(String.class);
}
public Object fromString(final String str) {
String s = cache.get(str);
if (s == null) {
cache.put(str, str);
s = str;
}
return s;
}
}
\ No newline at end of file
......@@ -172,7 +172,8 @@ public class RobustReflectionConverter implements Converter {
}
protected void marshallField(final MarshallingContext context, Object newObj, Field field) {
context.convertAnother(newObj);
Converter converter = mapper.getLocalConverter(field.getDeclaringClass(), field.getName());
context.convertAnother(newObj, converter);
}
public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
......@@ -287,7 +288,8 @@ public class RobustReflectionConverter implements Converter {
}
protected Object unmarshalField(final UnmarshallingContext context, final Object result, Class type, Field field) {
return context.convertAnother(result, type);
Converter converter = mapper.getLocalConverter(field.getDeclaringClass(), field.getName());
return context.convertAnother(result, type, converter);
}
private Map writeValueToImplicitCollection(UnmarshallingContext context, Object value, Map implicitCollections, Object result, String itemFieldName) {
......
......@@ -136,6 +136,7 @@ import hudson.security.AccessControlled;
import hudson.security.AuthorizationStrategy;
import hudson.security.BasicAuthenticationFilter;
import hudson.security.FederatedLoginService;
import hudson.security.FullControlOnceLoggedInAuthorizationStrategy;
import hudson.security.HudsonFilter;
import hudson.security.LegacyAuthorizationStrategy;
import hudson.security.LegacySecurityRealm;
......@@ -1226,12 +1227,17 @@ public class Jenkins extends AbstractCIBase implements ModifiableItemGroup<TopLe
*/
@Exported(name="jobs")
public List<TopLevelItem> getItems() {
if (authorizationStrategy instanceof AuthorizationStrategy.Unsecured ||
authorizationStrategy instanceof FullControlOnceLoggedInAuthorizationStrategy) {
return new ArrayList(items.values());
}
List<TopLevelItem> viewableItems = new ArrayList<TopLevelItem>();
for (TopLevelItem item : items.values()) {
if (item.hasPermission(Item.READ))
viewableItems.add(item);
}
return viewableItems;
}
......@@ -1537,11 +1543,7 @@ public class Jenkins extends AbstractCIBase implements ModifiableItemGroup<TopLe
* Gets the slave node of the give name, hooked under this Hudson.
*/
public Node getNode(String name) {
for (Node s : getNodes()) {
if(s.getNodeName().equals(name))
return s;
}
return null;
return slaves.getNode(name);
}
/**
......@@ -1560,7 +1562,7 @@ public class Jenkins extends AbstractCIBase implements ModifiableItemGroup<TopLe
* represents the master.
*/
public List<Node> getNodes() {
return Collections.unmodifiableList(slaves);
return slaves;
}
/**
......@@ -1588,11 +1590,6 @@ public class Jenkins extends AbstractCIBase implements ModifiableItemGroup<TopLe
}
public void setNodes(List<? extends Node> nodes) throws IOException {
// make sure that all names are unique
Set<String> names = new HashSet<String>();
for (Node n : nodes)
if(!names.add(n.getNodeName()))
throw new IllegalArgumentException(n.getNodeName()+" is defined more than once");
this.slaves = new NodeList(nodes);
updateComputerList();
trimLabels();
......@@ -2655,9 +2652,13 @@ public class Jenkins extends AbstractCIBase implements ModifiableItemGroup<TopLe
// issue the requests all at once
Map<String,Future<Map<String,String>>> future = new HashMap<String, Future<Map<String, String>>>();
for (Computer c : getComputers()) {
future.put(c.getName(), RemotingDiagnostics.getThreadDumpAsync(c.getChannel()));
}
if (toComputer() == null) {
future.put("master", RemotingDiagnostics.getThreadDumpAsync(MasterComputer.localChannel));
}
// if the result isn't available in 5 sec, ignore that.
// this is a precaution against hang nodes
......@@ -3607,7 +3608,7 @@ public class Jenkins extends AbstractCIBase implements ModifiableItemGroup<TopLe
*/
public static final XStream2 XSTREAM2 = (XStream2)XSTREAM;
private static final int TWICE_CPU_NUM = Runtime.getRuntime().availableProcessors() * 2;
private static final int TWICE_CPU_NUM = Math.max(4, Runtime.getRuntime().availableProcessors() * 2);
/**
* Thread pool used to load configuration in parallel, to improve the start up time.
......
......@@ -39,6 +39,7 @@ import hudson.util.DescribableList;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import java.util.Set;
import org.apache.commons.io.FileUtils;
......@@ -48,8 +49,9 @@ import org.apache.commons.io.FileUtils;
*/
public class NodeListTest extends TestCase {
static class DummyNode extends Node {
String nodeName = Long.toString(new Random().nextLong());
public String getNodeName() {
throw new UnsupportedOperationException();
return nodeName;
}
public void setNodeName(String name) {
......@@ -112,9 +114,7 @@ public class NodeListTest extends TestCase {
}
public void testSerialization() throws Exception {
NodeList nl = new NodeList();
nl.add(new DummyNode());
nl.add(new EphemeralNode());
NodeList nl = new NodeList(new DummyNode(), new EphemeralNode());
File tmp = File.createTempFile("test","test");
try {
......
......@@ -30,6 +30,8 @@ import hudson.maven.MavenBuildProxy;
import hudson.model.Api;
import hudson.model.BuildListener;
import hudson.model.FingerprintMap;
import hudson.model.Run;
import hudson.util.LRUStringConverter;
import jenkins.model.Jenkins;
import hudson.util.HttpResponses;
......@@ -68,6 +70,11 @@ import java.util.logging.Logger;
*/
@ExportedBean
public final class MavenArtifact implements Serializable {
static {
Run.XSTREAM.registerLocalConverter(MavenArtifact.class, "md5sum", new LRUStringConverter(5000));
}
/**
* Basic parameters of a Maven artifact.
*/
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册