Skip to content

Commit

Permalink
merged pull request #342
Browse files Browse the repository at this point in the history
  • Loading branch information
kohsuke committed Feb 6, 2012
2 parents 7028097 + 58e0ea4 commit acad637
Show file tree
Hide file tree
Showing 16 changed files with 196 additions and 58 deletions.
9 changes: 0 additions & 9 deletions core/src/main/java/hudson/WebAppMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,15 +217,6 @@ public void run() {
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;
Expand Down
44 changes: 27 additions & 17 deletions core/src/main/java/hudson/model/AbstractBuild.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -71,6 +72,8 @@
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;
Expand Down Expand Up @@ -284,7 +287,7 @@ public final FilePath getModuleRoot() {
public FilePath[] getModuleRoots() {
FilePath ws = getWorkspace();
if (ws==null) return null;
return getParent().getScm().getModuleRoots(ws,this);
return getParent().getScm().getModuleRoots(ws, this);
}

/**
Expand Down Expand Up @@ -570,7 +573,7 @@ private void checkout(BuildListener listener) throws Exception {
// 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"))) {
Expand Down Expand Up @@ -631,7 +634,7 @@ public final void post(BuildListener listener) throws Exception {
HashSet<String> r = new HashSet<String>();
for (User u : getCulprits())
r.add(u.getId());
culprits = r;
culprits = ImmutableSortedSet.copyOf(r);
CheckPoint.CULPRITS_DETERMINED.report();
}
}
Expand Down Expand Up @@ -750,27 +753,34 @@ public Collection<Fingerprint> getBuildFingerprints() {
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.
*
* @return never null.
*/
@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);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/model/Hudson.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public Slave getSlave(String name) {
* Use {@link #getNodes()}. Since 1.252.
*/
public List<Slave> getSlaves() {
return (List)Collections.unmodifiableList(slaves);
return (List)slaves;
}

/**
Expand Down
5 changes: 2 additions & 3 deletions core/src/main/java/hudson/model/Run.java
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ protected Run(JobT job, long timestamp) {
this.project = job;
this.timestamp = timestamp;
this.state = State.NOT_STARTED;
getRootDir().mkdirs();
}

/**
Expand Down Expand Up @@ -848,9 +849,7 @@ public Descriptor getDescriptorByName(String className) {
* 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());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/model/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ public String getDisplayName() {
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);
Expand Down
7 changes: 7 additions & 0 deletions core/src/main/java/hudson/scm/NullChangeLogParser.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,14 @@
* @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;
}
}
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/scm/NullSCM.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public boolean checkout(AbstractBuild<?,?> build, Launcher launcher, FilePath re
}

public ChangeLogParser createChangeLogParser() {
return new NullChangeLogParser();
return NullChangeLogParser.INSTANCE;
}

@Extension
Expand Down
80 changes: 76 additions & 4 deletions core/src/main/java/hudson/slaves/NodeList.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@
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;

/**
Expand All @@ -43,22 +46,91 @@
*
* @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) {
Expand Down
3 changes: 1 addition & 2 deletions core/src/main/java/hudson/tasks/Fingerprinter.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
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;
Expand Down Expand Up @@ -65,7 +64,6 @@
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;
Expand Down Expand Up @@ -294,6 +292,7 @@ public boolean isApplicable(Class<? extends AbstractProject> jobType) {
* Action for displaying fingerprints.
*/
public static final class FingerprintAction implements RunAction {

private final AbstractBuild build;

/**
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/java/hudson/tasks/MailMessageIdAction.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -34,9 +37,15 @@
* @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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ public static abstract class Data {
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;
Expand Down
41 changes: 41 additions & 0 deletions core/src/main/java/hudson/util/LRUStringConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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;
}
}
Loading

0 comments on commit acad637

Please sign in to comment.