Skip to content

Commit e89a4d5

Browse files
authored
Merge pull request #24 from refactoring-ai/feature/session-per-project
#4 Feature/session per project
2 parents 725483c + 8af3ccc commit e89a4d5

File tree

7 files changed

+109
-142
lines changed

7 files changed

+109
-142
lines changed

src/main/java/refactoringml/App.java

+14-9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.eclipse.jgit.lib.Repository;
1212
import org.eclipse.jgit.revwalk.RevCommit;
1313
import org.eclipse.jgit.revwalk.RevWalk;
14+
import org.hibernate.Transaction;
1415
import org.refactoringminer.api.GitHistoryRefactoringMiner;
1516
import org.refactoringminer.api.GitService;
1617
import org.refactoringminer.api.Refactoring;
@@ -26,6 +27,7 @@
2627
import java.io.IOException;
2728
import java.util.*;
2829
import java.util.stream.Collectors;
30+
2931
import static refactoringml.util.FilePathUtils.enforceUnixPaths;
3032
import static refactoringml.util.FilePathUtils.lastSlashDir;
3133
import static refactoringml.util.FileUtils.createTmpDir;
@@ -159,7 +161,12 @@ public Project run () throws Exception {
159161
if (currentCommit.getParentCount() > 1)
160162
continue;
161163

162-
processCommit(currentCommit, commitNumber, miner, handler, refactoringAnalyzer, processMetrics);
164+
try {
165+
processCommit(currentCommit, commitNumber, miner, handler, refactoringAnalyzer, processMetrics);
166+
}
167+
catch (Exception e) {
168+
log.error("Could not process commit {} on project {}", currentCommit, project, e);
169+
}
163170
commitNumber += 1;
164171
}
165172
walk.close();
@@ -168,11 +175,12 @@ public Project run () throws Exception {
168175
// note that if this process crashes, finished date will be equals to null in the database
169176
project.setFinishedDate(Calendar.getInstance());
170177
project.setExceptions(exceptionsCount);
171-
db.updateComplete(project);
178+
project = db.mergeComplete(project);
172179

173180
logProjectStatistics(startProjectTime);
174181
return project;
175182
} finally {
183+
db.close();
176184
// delete the tmp dir that stores the project
177185
FileUtils.deleteDirectory(new File(currentTempDir));
178186
}
@@ -212,9 +220,8 @@ private Project initProject(Git git) throws GitAPIException, IOException {
212220
private void processCommit(RevCommit currentCommit, int commitNumber, GitHistoryRefactoringMiner miner, RefactoringHandler handler, RefactoringAnalyzer refactoringAnalyzer, ProcessMetricsCollector processMetrics){
213221
long startCommitTime = System.currentTimeMillis();
214222
String commitHash = currentCommit.getId().getName();
223+
Transaction t = db.beginTransaction();
215224
try{
216-
db.openSession();
217-
218225
refactoringsToProcess = null;
219226
commitIdToProcess = null;
220227

@@ -253,15 +260,13 @@ private void processCommit(RevCommit currentCommit, int commitNumber, GitHistory
253260
Set<ImmutablePair<String, String>> jGitRenames = getJGitRenames(entries);
254261
processMetrics.collectMetrics(currentCommit, superCommitMetaData, allRefactoringCommits, entries, refactoringRenames, jGitRenames);
255262
long startTimeTransaction = System.currentTimeMillis();
256-
db.commit();
263+
t.commit();
257264
log.debug("Committing the transaction for commit " + commitHash + " took " + (System.currentTimeMillis() - startTimeTransaction) + " milliseconds.");
258265
} catch (Exception e) {
259266
exceptionsCount++;
260267
log.error("Unhandled exception when collecting commit data for commit: " + commitHash + createErrorState(commitHash, project), e);
261-
db.rollback(createErrorState(commitHash, project));
262-
} finally {
263-
db.close();
264-
}
268+
db.rollback(t, createErrorState(commitHash, project));
269+
}
265270
long elapsedCommitTime = System.currentTimeMillis() - startCommitTime;
266271
log.debug("Processing commit " + commitHash + " took " + elapsedCommitTime + " milliseconds.");
267272
}

src/main/java/refactoringml/ProcessMetricsCollector.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ private void collectProcessMetricsOfRefactoredCommit(CommitMetaData superCommitM
6262
new ProcessMetrics(0, 0, 0, 0, 0);
6363

6464
refactoringCommit.setProcessMetrics(dbProcessMetrics);
65-
db.update(refactoringCommit);
65+
db.merge(refactoringCommit);
6666

6767
pmDatabase.reportRefactoring(fileName, superCommitMetaData);
6868
}

src/main/java/refactoringml/RunQueue.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import org.apache.logging.log4j.LogManager;
55
import org.apache.logging.log4j.Logger;
66
import org.apache.logging.log4j.docker.DockerLookup;
7+
import org.hibernate.SessionFactory;
8+
79
import refactoringml.db.Database;
810
import refactoringml.db.HibernateConfig;
911
import refactoringml.util.PropertiesUtils;
@@ -25,7 +27,7 @@ public class RunQueue {
2527
private File failedProjectsFile;
2628

2729
public final static String QUEUE_NAME = "refactoring";
28-
private final Database db;
30+
private final SessionFactory sf;
2931
private String storagePath;
3032
private String host;
3133
private final boolean storeFullSourceCode;
@@ -42,7 +44,7 @@ public RunQueue(String host, String url, String user, String pwd, String storage
4244
failedProjectsFile = new File(enforceUnixPaths(PropertiesUtils.getProperty("failedProjectsFile") + "_" + containerName));
4345
failedProjectsFile.getParentFile().mkdirs();
4446

45-
db = new Database(HibernateConfig.getSessionFactory(url, user, pwd));
47+
sf = HibernateConfig.getSessionFactory(url, user, pwd);
4648
log.debug(toString());
4749
}
4850

@@ -112,7 +114,7 @@ private void shutdown(Channel channel) throws IOException {
112114
if (channel != null && channel.isOpen())
113115
channel.getConnection().close();
114116
//shutdown the connection with the MYSQL database
115-
db.shutdown();
117+
sf.close();
116118
//end the worker
117119
System.exit(0);
118120
}
@@ -126,7 +128,7 @@ private void processRepository(String message) throws IOException {
126128
String projectInfo = gitUrl + ", " + dataset;
127129
appendToFile(failedProjectsFile, projectInfo + "\n");
128130
try {
129-
new App(dataset, gitUrl, storagePath, db, storeFullSourceCode).run();
131+
new App(dataset, gitUrl, storagePath, new Database(sf.openSession()), storeFullSourceCode).run();
130132
} catch (org.eclipse.jgit.api.errors.TransportException te){
131133
storeFailedProject(gitUrl, "Repository not available", te);
132134
} catch (Exception e) {
@@ -150,6 +152,6 @@ public String toString(){
150152
"host = " + host + "\n" +
151153
"storagePath = " + storagePath + "\n" +
152154
"storeFullSourceCode = " + storeFullSourceCode +
153-
"db = " + db.toString() + "}";
155+
"sf = " + sf.toString() + "}";
154156
}
155157
}

src/main/java/refactoringml/RunSingleProject.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,14 @@ public static void main(String[] args) throws Exception {
5757

5858
Database db = null;
5959
try (SessionFactory sf = HibernateConfig.getSessionFactory(url, user, pwd)) {
60-
db = new Database(sf);
61-
} catch(Exception e) {
62-
log.fatal("Error when connecting to the Database: ", e);
60+
try {
61+
db = new Database(sf.openSession());
62+
} catch(Exception e) {
63+
log.error("Error when connecting to the Database: ", e);
64+
}
6365
}
66+
67+
6468
new App(datasetName, gitUrl, storagePath, db, storeFullSourceCode).run();
6569

6670
}

src/main/java/refactoringml/db/Database.java

+53-85
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,112 @@
11
package refactoringml.db;
22

3+
import java.sql.Connection;
4+
import java.sql.SQLException;
5+
36
import org.apache.logging.log4j.LogManager;
47
import org.apache.logging.log4j.Logger;
58
import org.hibernate.Session;
6-
import org.hibernate.SessionFactory;
9+
import org.hibernate.Transaction;
710
import org.hibernate.TransactionException;
811
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
9-
import java.sql.Connection;
10-
import java.sql.SQLException;
1112

1213
public class Database {
13-
private SessionFactory sf;
14-
private Session session;
14+
private final Session session;
1515

1616
private static final Logger log = LogManager.getLogger(Database.class);
1717

18-
public Database(SessionFactory sf) {
19-
this.sf = sf;
20-
}
21-
22-
public void openSession() {
23-
// if there's an open session, let's close it first.
24-
// this should not happen, though, only due to bad logic
25-
if(this.session!=null) {
26-
log.error("Session is open, but we are opening another one!");
27-
close();
28-
}
29-
30-
this.session = sf.openSession();
31-
session.beginTransaction();
18+
public Database(Session session) {
19+
this.session = session;
3220
}
3321

34-
//shutdown the session factory and all connections
35-
public void shutdown(){
36-
close();
37-
sf.close();
38-
sf = null;
22+
public void close() {
23+
session.close();
3924
}
4025

41-
public void commit() {
42-
this.session.getTransaction().commit();
26+
public Transaction beginTransaction() {
27+
return session.beginTransaction();
4328
}
4429

4530
public void persist(Object obj) {
4631
session.persist(obj);
4732
}
4833

49-
//Handles all the logic to persist an object to the database
50-
public void persistComplete(Object obj){
51-
openSession();
52-
persist(obj);
53-
commit();
54-
close();
34+
public <T> T merge(T toMerge) {
35+
return (T) session.merge(toMerge);
5536
}
5637

57-
//Handles all the logic to update an object to the database
58-
public void updateComplete(Object obj){
59-
openSession();
60-
update(obj);
61-
commit();
62-
close();
38+
public void persistComplete(Object toPersist) {
39+
Transaction t = beginTransaction();
40+
persist(toPersist);
41+
t.commit();
6342
}
6443

65-
public void update(Object obj) {
66-
session.update(obj);
67-
}
44+
public <T> T mergeComplete(T toMerge) {
45+
Transaction t = beginTransaction();
46+
T merged = merge(toMerge);
47+
t.commit();
48+
return merged;
6849

69-
public void close() {
70-
try {
71-
if (session != null)
72-
session.close();
73-
} catch(Exception e) {
74-
// what to do? this really shouldn't happen.
75-
log.error("Error when closing the connection to the Database: ", e);
76-
} finally {
77-
this.session = null;
78-
}
7950
}
8051

8152
public boolean projectExists(String gitUrl) {
82-
Session shortSession = sf.openSession();
83-
boolean exists = shortSession.createQuery("from Project p where p.gitUrl = :gitUrl")
84-
.setParameter("gitUrl", gitUrl)
85-
.list().size() > 0;
86-
shortSession.close();
87-
88-
return exists;
53+
return !session.createQuery("from Project p where p.gitUrl = :gitUrl").setParameter("gitUrl", gitUrl).list()
54+
.isEmpty();
8955
}
9056

91-
public long findAllRefactoringCommits(long projectId) { return findAllInstances("RefactoringCommit", projectId); }
57+
public long findAllRefactoringCommits(long projectId) {
58+
return findAllInstances("RefactoringCommit", projectId);
59+
}
9260

93-
public long findAllStableCommits(long projectId) { return findAllInstances("StableCommit", projectId); }
61+
public long findAllStableCommits(long projectId) {
62+
return findAllInstances("StableCommit", projectId);
63+
}
9464

95-
private long findAllInstances(String instance, long projectId){
96-
Session shortSession = sf.openSession();
65+
private long findAllInstances(String instance, long projectId) {
9766
String query = "Select count(*) From " + instance + " where " + instance + ".project_id = " + projectId;
98-
Object result = shortSession.createSQLQuery(query).getSingleResult();
99-
shortSession.close();
67+
Object result = session.createSQLQuery(query).getSingleResult();
10068
return Long.parseLong(result.toString());
10169
}
10270

10371
public long findAllStableCommits(long projectId, int level) {
104-
Session shortSession = sf.openSession();
105-
String query = "Select count(*) From StableCommit where StableCommit.project_id = " + projectId + " AND StableCommit.commitThreshold = " + level;
106-
Object result = shortSession.createSQLQuery(query).getSingleResult();
107-
shortSession.close();
72+
String query = "Select count(*) From StableCommit where StableCommit.project_id = " + projectId
73+
+ " AND StableCommit.commitThreshold = " + level;
74+
Object result = session.createSQLQuery(query).getSingleResult();
10875
return Long.parseLong(result.toString());
10976
}
11077

111-
//safely rollback a transaction with the db
112-
public void rollback(String logExtension) {
113-
//this session object itself should never be null, thus we don't check for it
114-
//nothing to do in this case, recovering the session or transaction is to much effort and the db takes care of a failed transaction
115-
if(!session.isOpen()) {
78+
// safely rollback a transaction with the db
79+
public void rollback(Transaction t,String logExtension) {
80+
// this session object itself should never be null, thus we don't check for it
81+
// nothing to do in this case, recovering the session or transaction is to much
82+
// effort and the db takes care of a failed transaction
83+
if (!session.isOpen()) {
11684
log.error("Session was already closed during attempted rollback: Doing Nothing." + logExtension);
11785
return;
11886
}
11987

120-
if(!session.isConnected()){
121-
try{
122-
Connection connection = sf.getSessionFactoryOptions().getServiceRegistry().
123-
getService(ConnectionProvider.class).getConnection();
88+
if (!session.isConnected()) {
89+
try {
90+
Connection connection = session.getSessionFactory().getSessionFactoryOptions().getServiceRegistry()
91+
.getService(ConnectionProvider.class).getConnection();
12492
session.reconnect(connection);
12593
} catch (SQLException e) {
12694
log.error("Failed to reconnect session object." + logExtension, e);
12795
}
12896
}
12997

130-
//standard case for a rollback
131-
if(session.isConnected() && session.getTransaction() != null) {
132-
try{
133-
session.getTransaction().rollback();
134-
return;
98+
// standard case for a rollback
99+
if (session.isConnected() && session.getTransaction() != null) {
100+
try {
101+
t.rollback();
135102
} catch (TransactionException e) {
136103
log.error("Failed to rollback session: " + session.toString() + logExtension, e);
137104
}
138105
} else {
139-
//other cases:
140-
//1. not connected to the DB : we could raise an error here, because something is probably wrong with the db
141-
//2. connected but no transaction object : nothing to do
106+
// other cases:
107+
// 1. not connected to the DB : we could raise an error here, because something
108+
// is probably wrong with the db
109+
// 2. connected but no transaction object : nothing to do
142110
log.error("Session is in a bad state: " + session.toString() + logExtension);
143111
}
144112
}

src/test/java/integration/DatabaseProjectTest.java

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package integration;
22

3-
import com.google.common.io.Files;
43
import org.apache.commons.io.FileUtils;
54
import org.hibernate.Session;
65
import org.hibernate.SessionFactory;
@@ -35,28 +34,24 @@ public class DatabaseProjectTest{
3534

3635
private Database db;
3736
private SessionFactory sf;
38-
private Session session;
3937

4038
@BeforeAll
4139
private void initTests() throws InterruptedException {
4240
outputDir = createTmpDir();
4341
tmpDir = createTmpDir();
4442

4543
sf = HibernateConfig.getSessionFactory(URL, USER, PASSWORD, false);
46-
db = new Database(sf);
4744
}
4845

4946
@BeforeEach
5047
void openSession() {
51-
session = sf.openSession();
48+
db = new Database(sf.openSession());
5249
}
5350

5451
@AfterEach
5552
void resetTests() {
5653
deleteProject(repo1);
5754
deleteProject(repo2);
58-
this.session.close();
59-
this.session = null;
6055
}
6156

6257
@AfterAll

0 commit comments

Comments
 (0)