Skip to content
Permalink
Browse files

[JENKINS-41124] So it seems there are some bold side-effects going on…

… in item constructors and we need to ensure those side effects take place in the correct directory
  • Loading branch information...
stephenc committed Jan 18, 2017
1 parent 76db05c commit e59d1474cd8751668e9fd84edc85df4933801efe
@@ -1798,7 +1798,14 @@ public void observe(@NonNull SCMHead head, @NonNull SCMRevision revision) {
listener.getLogger().println("Ignoring duplicate branch project " + rawName);
return;
}
project = _factory.newInstance(branch);
MultiBranchProjectDescriptor.BranchNameKey branchNameKey =
MultiBranchProjectDescriptor.ChildNameGeneratorImpl.INSTANCE
.beforeNewProject(MultiBranchProject.this, encodedName, branch);
try {
project = _factory.newInstance(branch);
} finally {
MultiBranchProjectDescriptor.ChildNameGeneratorImpl.INSTANCE.afterNewProject(branchNameKey);
}
if (!project.getName().equals(encodedName)) {
throw new IllegalStateException(
"Name of created project " + project + " did not match expected " + encodedName);
@@ -40,6 +40,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.WeakHashMap;
import javax.annotation.CheckForNull;
import jenkins.model.Jenkins;
import jenkins.scm.api.SCMSourceDescriptor;
@@ -223,17 +224,39 @@ public boolean isIconConfigurable() {
public static class ChildNameGeneratorImpl<P extends Job<P, R> & TopLevelItem,
R extends Run<P, R>> extends ChildNameGenerator<MultiBranchProject<P,R>,P> {

public static final ChildNameGeneratorImpl INSTANCE = new ChildNameGeneratorImpl();
/*package*/ static final ChildNameGeneratorImpl INSTANCE = new ChildNameGeneratorImpl();
private final WeakHashMap<BranchNameKey, Branch> awaitingCreation =
new WeakHashMap<>();

public synchronized BranchNameKey beforeNewProject(
@NonNull MultiBranchProject<?,?> parent, @NonNull String name, Branch branch) {
BranchNameKey key = new BranchNameKey(parent, name);
awaitingCreation.put(key, branch);
return key;
}

public synchronized void afterNewProject(BranchNameKey key) {
awaitingCreation.remove(key); // not critical as will get cleared by GC but we can help it out too
}


@Override
@CheckForNull
public String itemNameFromItem(@NonNull MultiBranchProject<P,R> parent, @NonNull P item) {
BranchProjectFactory<P, R> factory = parent.getProjectFactory();
if (factory.isProject(item)) {
return NameEncoder.encode(factory.getBranch(item).getName());
} else {
return null;
}
if (item.getName() != null) {
Branch branch;
synchronized (this) {
branch = awaitingCreation.get(new BranchNameKey(parent, item.getName()));
}
if (branch != null) {
return NameEncoder.encode(branch.getName());
}
}
return null;
}

@Override
@@ -242,9 +265,17 @@ public String dirNameFromItem(@NonNull MultiBranchProject<P,R> parent, @NonNull
BranchProjectFactory<P, R> factory = parent.getProjectFactory();
if (factory.isProject(item)) {
return NameMangler.apply(factory.getBranch(item).getName());
} else {
return null;
}
if (item.getName() != null) {
Branch branch;
synchronized (this) {
branch = awaitingCreation.get(new BranchNameKey(parent, item.getName()));
}
if (branch != null) {
return NameMangler.apply(branch.getName());
}
}
return null;
}

@Override
@@ -258,6 +289,40 @@ public String itemNameFromLegacy(@NonNull MultiBranchProject<P, R> parent, @NonN
public String dirNameFromLegacy(@NonNull MultiBranchProject<P, R> parent, @NonNull String legacyDirName) {
return NameMangler.apply(NameEncoder.decode(legacyDirName));
}

}

/*package*/ static class BranchNameKey {
private final MultiBranchProject<?, ?> parent;
private final String projectName;

public BranchNameKey(MultiBranchProject<?, ?> parent, String projectName) {
this.parent = parent;
this.projectName = projectName;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

BranchNameKey that = (BranchNameKey) o;

if (parent != that.parent) {
return false;
}
return projectName.equals(that.projectName);
}

@Override
public int hashCode() {
return projectName.hashCode();
}

}

}
@@ -771,23 +771,52 @@ public boolean isIconConfigurable() {
private static class ChildNameGeneratorImpl extends ChildNameGenerator<OrganizationFolder, MultiBranchProject<?,?>> {

private static final ChildNameGeneratorImpl INSTANCE = new ChildNameGeneratorImpl();
private final WeakHashMap<ProjectNamePropertyKey, ProjectNameProperty> awaitingCreation = new WeakHashMap<>();

public synchronized ProjectNamePropertyKey beforeNewProject(@NonNull OrganizationFolder parent, @NonNull String name, ProjectNameProperty property) {
ProjectNamePropertyKey key = new ProjectNamePropertyKey(parent, name);
awaitingCreation.put(key, property);
return key;
}

public synchronized void afterNewProject(ProjectNamePropertyKey key) {
awaitingCreation.remove(key); // not critical as will get cleared by GC but we can help it out too
}

@Override
@CheckForNull
public String itemNameFromItem(@NonNull OrganizationFolder parent, @NonNull MultiBranchProject<?, ?> item) {
ProjectNameProperty property = item.getProperties().get(ProjectNameProperty.class);
if (property != null) {
return NameEncoder.encode(property.getName());
} else {
return null;
}
if (item.getName() != null) {
synchronized (this) {
property = awaitingCreation.get(new ProjectNamePropertyKey(parent, item.getName()));
}
if (property != null) {
return NameEncoder.encode(property.getName());
}
}
return null;
}

@Override
@CheckForNull
public String dirNameFromItem(@NonNull OrganizationFolder parent, @NonNull MultiBranchProject<?, ?> item) {
ProjectNameProperty property = item.getProperties().get(ProjectNameProperty.class);
return property != null ? NameMangler.apply(property.getName()) : null;
if (property != null) {
return NameMangler.apply(property.getName());
}
if (item.getName() != null) {
synchronized (this) {
property = awaitingCreation.get(new ProjectNamePropertyKey(parent, item.getName()));
}
if (property != null) {
return NameMangler.apply(property.getName());
}
}
return null;
}

@Override
@@ -803,6 +832,38 @@ public String dirNameFromLegacy(@NonNull OrganizationFolder parent, @NonNull Str
}
}

private static class ProjectNamePropertyKey {
private final OrganizationFolder parent;
private final String projectName;

public ProjectNamePropertyKey(OrganizationFolder parent, String projectName) {
this.parent = parent;
this.projectName = projectName;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

ProjectNamePropertyKey that = (ProjectNamePropertyKey) o;

if (parent != that.parent) {
return false;
}
return projectName.equals(that.projectName);
}

@Override
public int hashCode() {
return projectName.hashCode();
}
}

/**
* Our scan.
*/
@@ -1159,15 +1220,23 @@ public void complete() throws IllegalStateException, InterruptedException {
listener.getLogger().println("Ignoring duplicate child " + projectName + " named " + folderName);
return;
}
MultiBranchProject<?, ?> project = factory.createNewProject(
OrganizationFolder.this, folderName, sources, attributes, listener
);
ProjectNameProperty property = new ProjectNameProperty(projectName);
ProjectNamePropertyKey propertyKey = ChildNameGeneratorImpl.INSTANCE
.beforeNewProject(OrganizationFolder.this, folderName, property);
MultiBranchProject<?, ?> project;
try {
project = factory.createNewProject(
OrganizationFolder.this, folderName, sources, attributes, listener
);
} finally {
ChildNameGeneratorImpl.INSTANCE.afterNewProject(propertyKey);
}
BulkChange bc = new BulkChange(project);
try {
if (!projectName.equals(folderName)) {
project.setDisplayName(projectName);
}
project.addProperty(new ProjectNameProperty(projectName));
project.addProperty(property);
project.setOrphanedItemStrategy(getOrphanedItemStrategy());
project.getSourcesList().addAll(createBranchSources());
try {

0 comments on commit e59d147

Please sign in to comment.
You can’t perform that action at this time.