3838import com .arcadedb .index .lsm .LSMTreeIndexAbstract ;
3939import com .arcadedb .log .LogManager ;
4040import com .arcadedb .schema .LocalSchema ;
41+ import com .arcadedb .utility .IntHashSet ;
4142import com .arcadedb .utility .RidHashSet ;
4243
4344import java .io .*;
@@ -545,8 +546,11 @@ public void commitFromReplica(final WALFile.WALTransaction buffer,
545546 }
546547
547548 try {
548- // LOCK FILES (IN ORDER, SO TO AVOID DEADLOCK)
549- final Set <Integer > modifiedFiles = new HashSet <>();
549+ // LOCK FILES (IN ORDER, SO TO AVOID DEADLOCK).
550+ // IntHashSet (zero-boxing) is used because this set is built on every commit
551+ // and the small Integer boxing churn shows up in young-gen GC pressure under
552+ // high transaction throughput.
553+ final IntHashSet modifiedFiles = new IntHashSet (buffer .pages .length + 4 );
550554
551555 for (final WALFile .WALPage p : buffer .pages )
552556 modifiedFiles .add (p .fileId );
@@ -620,7 +624,7 @@ public TransactionPhase1 commit1stPhase(final boolean isLeader) {
620624 ((LocalBucket ) database .getSchema ().getBucketById (rid .getBucketId ())).fetchPageInTransaction (rid );
621625 }
622626
623- final Set < Integer > modifiedFiles = lockFilesFromChanges ();
627+ final IntHashSet modifiedFiles = lockFilesFromChanges ();
624628
625629 if (explicitLockedFiles != null )
626630 checkExplicitLocks (modifiedFiles );
@@ -866,7 +870,7 @@ public void setStatus(final STATUS status) {
866870 this .status = status ;
867871 }
868872
869- protected void explicitLock (final Set < Integer > filesToLock ) {
873+ protected void explicitLock (final IntHashSet filesToLock ) {
870874 if (explicitLockedFiles != null )
871875 throw new TransactionException ("Explicit lock already acquired" );
872876
@@ -879,8 +883,8 @@ protected void explicitLock(final Set<Integer> filesToLock) {
879883 explicitLockedFiles = lockFilesInOrder (filesToLock );
880884 }
881885
882- private Set < Integer > lockFilesFromChanges () {
883- final Set < Integer > modifiedFiles = new HashSet <>( );
886+ private IntHashSet lockFilesFromChanges () {
887+ final IntHashSet modifiedFiles = new IntHashSet ( modifiedPages . size () + 16 );
884888
885889 for (final PageId p : modifiedPages .keySet ())
886890 modifiedFiles .add (p .getFileId ());
@@ -890,15 +894,16 @@ private Set<Integer> lockFilesFromChanges() {
890894
891895 indexChanges .addFilesToLock (modifiedFiles );
892896
893- modifiedFiles .addAll (newPageCounters .keySet ());
897+ for (final Integer fid : newPageCounters .keySet ())
898+ modifiedFiles .add (fid );
894899
895900 return modifiedFiles ;
896901 }
897902
898- private List <Integer > lockFilesInOrder (final Set < Integer > files ) {
903+ private List <Integer > lockFilesInOrder (final IntHashSet files ) {
899904 final long timeout = database .getConfiguration ().getValueAsLong (GlobalConfiguration .COMMIT_LOCK_TIMEOUT );
900905
901- final List <Integer > locked = database .getTransactionManager ().tryLockFiles (files , timeout , getRequester ());
906+ final List <Integer > locked = database .getTransactionManager ().tryLockFiles (files . toArray () , timeout , getRequester ());
902907
903908 // CHECK IF ALL THE LOCKED FILES STILL EXIST. FILE MISSING CAN HAPPEN IN CASE OF INDEX COMPACTION OR DROP OF A BUCKET OR AN INDEX
904909 for (Integer f : locked )
@@ -915,9 +920,14 @@ private List<Integer> lockFilesInOrder(final Set<Integer> files) {
915920 return locked ;
916921 }
917922
918- private void checkExplicitLocks (final Set <Integer > modifiedFiles ) {
919- // CHECK THE LOCKED FILES ARE ALL LOCKED ALREADY
920- if (!explicitLockedFiles .containsAll (modifiedFiles )) {
923+ private void checkExplicitLocks (final IntHashSet modifiedFiles ) {
924+ // CHECK THE LOCKED FILES ARE ALL LOCKED ALREADY: every modified file must already be in explicitLockedFiles.
925+ final boolean [] missing = { false };
926+ modifiedFiles .forEach (fid -> {
927+ if (!missing [0 ] && !explicitLockedFiles .contains (fid ))
928+ missing [0 ] = true ;
929+ });
930+ if (missing [0 ]) {
921931 boolean anyMigration = false ;
922932 // CHECK FOR ANY MIGRATED FILES (INDEX COMPACTION)
923933 final List <Integer > migratedFileIds = new ArrayList <>(explicitLockedFiles .size ());
@@ -932,13 +942,23 @@ private void checkExplicitLocks(final Set<Integer> modifiedFiles) {
932942 }
933943 }
934944
935- if (anyMigration && migratedFileIds .containsAll (modifiedFiles ))
936- // FOUND MIGRATED FILE(S), FORCE THE CLIENT TO RETRY THE OPERATION
937- throw new ConcurrentModificationException (
938- "Error on commit transaction: some files have been migrated, please retry the operation" );
945+ if (anyMigration ) {
946+ // Check if EVERY modifiedFiles entry is in migratedFileIds
947+ final HashSet <Integer > migratedSet = new HashSet <>(migratedFileIds );
948+ final boolean [] allMigrated = { true };
949+ modifiedFiles .forEach (fid -> {
950+ if (allMigrated [0 ] && !migratedSet .contains (fid ))
951+ allMigrated [0 ] = false ;
952+ });
953+ if (allMigrated [0 ])
954+ // FOUND MIGRATED FILE(S), FORCE THE CLIENT TO RETRY THE OPERATION
955+ throw new ConcurrentModificationException (
956+ "Error on commit transaction: some files have been migrated, please retry the operation" );
957+ }
939958
940959 // ERROR: NOT ALL THE MODIFIED FILES ARE LOCKED
941- final HashSet <Integer > left = new HashSet <>(modifiedFiles );
960+ final HashSet <Integer > left = new HashSet <>(modifiedFiles .size ());
961+ modifiedFiles .forEach (left ::add );
942962 left .removeAll (explicitLockedFiles );
943963
944964 final Set <String > resourceNames = left .stream ().map ((fileId -> database .getSchema ().getFileById (fileId ).getName ()))
0 commit comments