Skip to content

Commit b7a33f2

Browse files
Unlock previously locked records when executing READ, WRITE, REWRITE, DELETE and CLOSE (#699)
* feat: set file status 92 when opening old files * fix: set file status 92 correctly * tests: add tests for opening old indexed files * test: fix flaky tests * fix: unlock records locked not by other processes * fix: unlock previous records when failing to lock a record * chore: unlock the previous record (write) * fix: unlock the previous record (rewrite) * fix: unlock previous records * Update libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolFile.java Co-authored-by: Copilot <[email protected]> * fix: an invalid comment * refactor: format Java files --------- Co-authored-by: Copilot <[email protected]>
1 parent d08f70c commit b7a33f2

File tree

3 files changed

+350
-6
lines changed

3 files changed

+350
-6
lines changed

libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolFile.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,24 @@ private static String concatString(String... strs) {
907907
return sb.toString();
908908
}
909909

910+
/**
911+
* This method is mainly for unlocking the indexed files.
912+
*
913+
* @return true if post-processing is successful, false otherwise.
914+
*/
915+
protected boolean postProcess() {
916+
return true;
917+
}
918+
919+
private void runPostProcess(AbstractCobolField fnstatus) {
920+
postProcess();
921+
// TODO: Implement error handling
922+
// boolean postProcessSucceeded = postProcess();
923+
// if(!postProcessSucceeded) {
924+
// this.saveStatus(COB_STATUS_30_PERMANENT_ERROR, fnstatus);
925+
// }
926+
}
927+
910928
/**
911929
* TODO: 準備中
912930
*
@@ -1408,21 +1426,25 @@ public void read(AbstractCobolField key, AbstractCobolField fnstatus, int readOp
14081426
if (this.flag_nonexistent) {
14091427
if (this.flag_first_read == 0) {
14101428
saveStatus(COB_STATUS_23_KEY_NOT_EXISTS, fnstatus);
1429+
runPostProcess(fnstatus);
14111430
return;
14121431
}
14131432
this.flag_first_read = 0;
14141433
saveStatus(COB_STATUS_10_END_OF_FILE, fnstatus);
1434+
runPostProcess(fnstatus);
14151435
return;
14161436
}
14171437

14181438
/* sequential read at the end of file is an error */
14191439
if (key == null) {
14201440
if (this.flag_end_of_file && (readOpts & COB_READ_PREVIOUS) == 0) {
14211441
saveStatus(COB_STATUS_46_READ_ERROR, fnstatus);
1442+
runPostProcess(fnstatus);
14221443
return;
14231444
}
14241445
if (this.flag_begin_of_file && (readOpts & COB_READ_PREVIOUS) != 0) {
14251446
saveStatus(COB_STATUS_46_READ_ERROR, fnstatus);
1447+
runPostProcess(fnstatus);
14261448
return;
14271449
}
14281450
}
@@ -1431,6 +1453,7 @@ public void read(AbstractCobolField key, AbstractCobolField fnstatus, int readOp
14311453
|| this.open_mode == COB_OPEN_OUTPUT
14321454
|| this.open_mode == COB_OPEN_EXTEND) {
14331455
saveStatus(COB_STATUS_47_INPUT_DENIED, fnstatus);
1456+
runPostProcess(fnstatus);
14341457
return;
14351458
}
14361459

@@ -1558,13 +1581,15 @@ public void write(AbstractCobolField rec, int opt, AbstractCobolField fnstatus)
15581581
|| this.open_mode == COB_OPEN_INPUT
15591582
|| this.open_mode == COB_OPEN_I_O) {
15601583
saveStatus(COB_STATUS_48_OUTPUT_DENIED, fnstatus);
1584+
runPostProcess(fnstatus);
15611585
return;
15621586
}
15631587
} else {
15641588
if (this.open_mode == COB_OPEN_CLOSED
15651589
|| this.open_mode == COB_OPEN_INPUT
15661590
|| this.open_mode == COB_OPEN_EXTEND) {
15671591
saveStatus(COB_STATUS_48_OUTPUT_DENIED, fnstatus);
1592+
runPostProcess(fnstatus);
15681593
return;
15691594
}
15701595
}
@@ -1578,6 +1603,7 @@ public void write(AbstractCobolField rec, int opt, AbstractCobolField fnstatus)
15781603

15791604
if (this.record.getSize() < this.record_min || this.record_max < this.record.getSize()) {
15801605
saveStatus(COB_STATUS_44_RECORD_OVERFLOW, fnstatus);
1606+
runPostProcess(fnstatus);
15811607
return;
15821608
}
15831609

@@ -1657,20 +1683,24 @@ public void rewrite(AbstractCobolField rec, int opt, AbstractCobolField fnstatus
16571683

16581684
if (this.open_mode == COB_OPEN_CLOSED || this.open_mode != COB_OPEN_I_O) {
16591685
saveStatus(COB_STATUS_49_I_O_DENIED, fnstatus);
1686+
runPostProcess(fnstatus);
16601687
return;
16611688
}
16621689
if (this.access_mode == COB_ACCESS_SEQUENTIAL && !readDone) {
16631690
saveStatus(COB_STATUS_43_READ_NOT_DONE, fnstatus);
1691+
runPostProcess(fnstatus);
16641692
return;
16651693
}
16661694
if (this.organization == COB_ORG_SEQUENTIAL) {
16671695
if (this.record.getSize() != rec.getSize()) {
16681696
saveStatus(COB_STATUS_44_RECORD_OVERFLOW, fnstatus);
1697+
runPostProcess(fnstatus);
16691698
return;
16701699
}
16711700
if (this.record_size != null) {
16721701
if (this.record.getSize() != this.record_size.getInt()) {
16731702
saveStatus(COB_STATUS_44_RECORD_OVERFLOW, fnstatus);
1703+
runPostProcess(fnstatus);
16741704
return;
16751705
}
16761706
}
@@ -1721,11 +1751,13 @@ public void delete(AbstractCobolField fnstatus) {
17211751

17221752
if (this.open_mode == COB_OPEN_CLOSED || this.open_mode != COB_OPEN_I_O) {
17231753
saveStatus(COB_STATUS_49_I_O_DENIED, fnstatus);
1754+
runPostProcess(fnstatus);
17241755
return;
17251756
}
17261757

17271758
if (this.access_mode == COB_ACCESS_SEQUENTIAL && !readDone) {
17281759
saveStatus(COB_STATUS_43_READ_NOT_DONE, fnstatus);
1760+
runPostProcess(fnstatus);
17291761
return;
17301762
}
17311763

libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolIndexedFile.java

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,9 @@ public int open_(String filename, int mode, int sharing) {
227227
return getConnectionStatus;
228228
}
229229

230-
if(fileExists) {
230+
if (fileExists) {
231231
int code = this.checkVersionOld();
232-
if(code != COB_STATUS_00_SUCCESS) {
232+
if (code != COB_STATUS_00_SUCCESS) {
233233
return code;
234234
}
235235
}
@@ -303,11 +303,12 @@ private int checkVersionOld() {
303303
IndexedFile p = this.filei;
304304
try (Statement st = p.connection.createStatement()) {
305305
String fileLockTableExistsSql =
306-
"select exists(select 1 from sqlite_master where type = 'table' and name = 'file_lock')";
306+
"select exists(select 1 from sqlite_master where type = 'table' and name ="
307+
+ " 'file_lock')";
307308
ResultSet fileLockTableExistsResultSet = st.executeQuery(fileLockTableExistsSql);
308309
if (fileLockTableExistsResultSet.next()) {
309310
boolean fileLockTableExists = fileLockTableExistsResultSet.getInt(1) == 1;
310-
if(!fileLockTableExists) {
311+
if (!fileLockTableExists) {
311312
return COB_STATUS_92_VERSION_INCOMPATIBLE;
312313
}
313314
} else {
@@ -700,15 +701,26 @@ private void unlockPreviousRecord() throws SQLException {
700701
String updateSql =
701702
String.format(
702703
"update %s set locked_by = null, process_id = null, locked_at = null where"
703-
+ " key = ?",
704+
+ " key = ? and locked_by = ?",
704705
getTableName(0));
705706
try (PreparedStatement updateStatement = p.connection.prepareStatement(updateSql)) {
706707
updateStatement.setBytes(1, previousLockedRecordKey);
708+
updateStatement.setString(2, this.getProcessUuid());
707709
updateStatement.executeUpdate();
708710
}
709711
previousLockedRecordKey = null;
710712
}
711713

714+
@Override
715+
protected boolean postProcess() {
716+
try {
717+
unlockPreviousRecord();
718+
} catch (SQLException e) {
719+
return false;
720+
}
721+
return true;
722+
}
723+
712724
private void unlockPreviousRecord(byte[] key) throws SQLException {
713725
if (previousLockedRecordKey == null) {
714726
previousLockedRecordKey = key;
@@ -718,10 +730,11 @@ private void unlockPreviousRecord(byte[] key) throws SQLException {
718730
String updateSql =
719731
String.format(
720732
"update %s set locked_by = null, process_id = null, locked_at = null where"
721-
+ " key = ?",
733+
+ " key = ? and locked_by = ?",
722734
getTableName(0));
723735
try (PreparedStatement updateStatement = p.connection.prepareStatement(updateSql)) {
724736
updateStatement.setBytes(1, previousLockedRecordKey);
737+
updateStatement.setString(2, this.getProcessUuid());
725738
updateStatement.executeUpdate();
726739
}
727740
previousLockedRecordKey = key;
@@ -756,10 +769,14 @@ public int read_(AbstractCobolField key, int readOpts) {
756769
try {
757770
if (checkOtherProcessLockedRecord(primaryKey)) {
758771
p.connection.rollback();
772+
unlockPreviousRecord();
773+
p.connection.commit();
759774
return COB_STATUS_51_RECORD_LOCKED;
760775
}
761776
if (!lockRecord(primaryKey)) {
762777
p.connection.rollback();
778+
unlockPreviousRecord();
779+
p.connection.commit();
763780
return COB_STATUS_30_PERMANENT_ERROR;
764781
}
765782
unlockPreviousRecord(primaryKey);
@@ -894,10 +911,14 @@ public int readNext(int readOpts) {
894911
try {
895912
if (checkOtherProcessLockedRecord(primaryKey)) {
896913
p.connection.rollback();
914+
unlockPreviousRecord();
915+
p.connection.commit();
897916
return COB_STATUS_51_RECORD_LOCKED;
898917
}
899918
if (!lockRecord(primaryKey)) {
900919
p.connection.rollback();
920+
unlockPreviousRecord();
921+
p.connection.commit();
901922
return COB_STATUS_30_PERMANENT_ERROR;
902923
}
903924
unlockPreviousRecord(primaryKey);
@@ -1069,6 +1090,12 @@ public int write_(int opt) {
10691090
} else if (this.access_mode == COB_ACCESS_SEQUENTIAL) {
10701091
byte[] keyBytes = p.key;
10711092
if (p.last_key.memcmp(keyBytes, keyBytes.length) > 0) {
1093+
try {
1094+
unlockPreviousRecord();
1095+
p.connection.commit();
1096+
} catch (SQLException e) {
1097+
return COB_STATUS_30_PERMANENT_ERROR;
1098+
}
10721099
return COB_STATUS_21_KEY_INVALID;
10731100
}
10741101
}
@@ -1145,6 +1172,12 @@ public int rewrite_(int opt) {
11451172

11461173
if (this.access_mode == COB_ACCESS_SEQUENTIAL
11471174
&& !IndexedCursor.matchKeyHead(p.key, DBT_SET(this.keys[0].getField()))) {
1175+
try {
1176+
unlockPreviousRecord();
1177+
p.connection.commit();
1178+
} catch (SQLException e) {
1179+
return COB_STATUS_30_PERMANENT_ERROR;
1180+
}
11481181
return COB_STATUS_21_KEY_INVALID;
11491182
}
11501183

0 commit comments

Comments
 (0)