mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
First round of optimisation to CardDb
This optimisation removes redundant queries when looking for cards by specificed Art Preference. getCardsFromSet has been worked-around, avoiding querying for potential candidates already in memory. A preliminary benchmark/tests is implemented too.
This commit is contained in:
@@ -465,7 +465,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
|||||||
// So now check whether the cards exists in the DB first,
|
// So now check whether the cards exists in the DB first,
|
||||||
// and select pick the card based on current SetPreference policy as a fallback
|
// and select pick the card based on current SetPreference policy as a fallback
|
||||||
Collection<PaperCard> cards = getAllCards(request.cardName);
|
Collection<PaperCard> cards = getAllCards(request.cardName);
|
||||||
if (cards == null)
|
if (cards.isEmpty()) // Never null being this a view in MultiMap
|
||||||
return null;
|
return null;
|
||||||
// Either No Edition has been specified OR as a fallback in case of any error!
|
// Either No Edition has been specified OR as a fallback in case of any error!
|
||||||
// get card using the default card art preference
|
// get card using the default card art preference
|
||||||
@@ -640,6 +640,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
|||||||
@Override
|
@Override
|
||||||
public boolean apply(PaperCard c) {
|
public boolean apply(PaperCard c) {
|
||||||
CardEdition ed = editions.get(c.getEdition());
|
CardEdition ed = editions.get(c.getEdition());
|
||||||
|
if (ed == null) return false;
|
||||||
if (releasedBeforeFlag)
|
if (releasedBeforeFlag)
|
||||||
return ed.getDate().before(releaseDate);
|
return ed.getDate().before(releaseDate);
|
||||||
else
|
else
|
||||||
@@ -648,22 +649,24 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cards.size() == 0) // Don't bother continuing! No card has been found!
|
|
||||||
return null;
|
|
||||||
|
|
||||||
/* 2. Retrieve cards based of [Frame]Set Preference
|
/* 2. Retrieve cards based of [Frame]Set Preference
|
||||||
================================================ */
|
================================================ */
|
||||||
|
|
||||||
// Collect the list of all editions found for target card
|
// Collect the list of all editions found for target card
|
||||||
LinkedHashSet<CardEdition> cardEditions = new LinkedHashSet<>();
|
List<CardEdition> cardEditions = new ArrayList<>();
|
||||||
|
Map<String, PaperCard> candidatesCard = new HashMap<>();
|
||||||
for (PaperCard card : cards) {
|
for (PaperCard card : cards) {
|
||||||
|
if (card.getArtIndex() != cr.artIndex)
|
||||||
|
continue;
|
||||||
String setCode = card.getEdition();
|
String setCode = card.getEdition();
|
||||||
|
CardEdition ed = null;
|
||||||
if (setCode.equals(CardEdition.UNKNOWN.getCode()))
|
if (setCode.equals(CardEdition.UNKNOWN.getCode()))
|
||||||
cardEditions.add(CardEdition.UNKNOWN);
|
ed = CardEdition.UNKNOWN;
|
||||||
else {
|
else
|
||||||
CardEdition ed = editions.get(card.getEdition());
|
ed = editions.get(card.getEdition());
|
||||||
if (ed != null)
|
if (ed != null) {
|
||||||
cardEditions.add(ed);
|
cardEditions.add(ed);
|
||||||
|
candidatesCard.put(setCode, card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Filter Cards Editions based on set preferences
|
// Filter Cards Editions based on set preferences
|
||||||
@@ -681,16 +684,19 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
|||||||
If this happens, we won't try to iterate over an empty list. Instead, we will fall back
|
If this happens, we won't try to iterate over an empty list. Instead, we will fall back
|
||||||
to original lists of editions (unfiltered, of course) AND STILL sorted according to chosen art preference.
|
to original lists of editions (unfiltered, of course) AND STILL sorted according to chosen art preference.
|
||||||
*/
|
*/
|
||||||
if (acceptedEditions.size() == 0)
|
if (acceptedEditions.isEmpty())
|
||||||
acceptedEditions.addAll(cardEditions);
|
acceptedEditions.addAll(cardEditions);
|
||||||
|
|
||||||
Collections.sort(acceptedEditions); // CardEdition correctly sort by (release) date
|
if (acceptedEditions.size() > 1) {
|
||||||
if (artPref.latestFirst)
|
Collections.sort(acceptedEditions); // CardEdition correctly sort by (release) date
|
||||||
Collections.reverse(acceptedEditions); // newest editions first
|
if (artPref.latestFirst)
|
||||||
|
Collections.reverse(acceptedEditions); // newest editions first
|
||||||
|
}
|
||||||
|
|
||||||
PaperCard candidate = null;
|
PaperCard candidate = null;
|
||||||
for (CardEdition ed : acceptedEditions) {
|
for (CardEdition ed : acceptedEditions) {
|
||||||
PaperCard cardFromSet = getCardFromSet(cr.cardName, ed, cr.artIndex, cr.isFoil);
|
PaperCard cardFromSet = candidatesCard.get(ed.getCode()); //getCardFromSet(cr.cardName, ed, cr.artIndex, cr.isFoil);
|
||||||
if (candidate == null && cardFromSet != null)
|
if (candidate == null)
|
||||||
// save the first card found, as the last backup in case no other candidate *with image* will be found
|
// save the first card found, as the last backup in case no other candidate *with image* will be found
|
||||||
candidate = cardFromSet;
|
candidate = cardFromSet;
|
||||||
|
|
||||||
@@ -699,8 +705,11 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
|||||||
break; // we're done here: found card **with Image**
|
break; // we're done here: found card **with Image**
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (candidate == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
//If any, we're sure that at least one candidate is always returned nevertheless it has image or not
|
//If any, we're sure that at least one candidate is always returned nevertheless it has image or not
|
||||||
return candidate; // any foil request already handled in getCardFromSet
|
return cr.isFoil ? candidate.getFoiled() : candidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package forge.card;
|
||||||
|
|
||||||
|
import forge.ImageKeys;
|
||||||
|
import forge.item.PaperCard;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.powermock.api.mockito.PowerMockito;
|
||||||
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
|
||||||
|
public class CardDbPerformanceTests extends CardDbTestCase {
|
||||||
|
|
||||||
|
private Set<String> fullDbCardNames = new TreeSet<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@BeforeMethod
|
||||||
|
public void setup() {
|
||||||
|
super.setup();
|
||||||
|
Collection<PaperCard> uniqueCards = this.cardDb.getUniqueCards();
|
||||||
|
for (PaperCard card : uniqueCards)
|
||||||
|
this.fullDbCardNames.add(card.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBenchmarkFullDbGetCardLegacyImplementation() {
|
||||||
|
int nRuns = 100;
|
||||||
|
long averageTime = 0;
|
||||||
|
long minTime = 10000; // 10 secs
|
||||||
|
long maxTime = 0;
|
||||||
|
for (int r = 1; r <= nRuns; r++) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
for (String name : this.fullDbCardNames) {
|
||||||
|
PaperCard card = this.legacyCardDb.getCard(name);
|
||||||
|
assertNotNull(card);
|
||||||
|
}
|
||||||
|
long timeRun = System.currentTimeMillis() - start;
|
||||||
|
averageTime += timeRun;
|
||||||
|
if (timeRun < minTime)
|
||||||
|
minTime = timeRun;
|
||||||
|
if (timeRun > maxTime)
|
||||||
|
maxTime = timeRun;
|
||||||
|
}
|
||||||
|
System.out.println("[LEGACY] Total Time (in sec): " + ((double) averageTime)/ 1000);
|
||||||
|
System.out.println("[LEGACY] Average Time (in sec): " + ((double) averageTime / nRuns)/ 1000);
|
||||||
|
System.out.println("[LEGACY] Best Time (in sec): " + ((double) minTime)/ 1000);
|
||||||
|
System.out.println("[LEGACY] Worst Time (in sec): " + ((double) maxTime)/ 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBenchmarkFullDbGetCardNewDbImplementation() {
|
||||||
|
int nRuns = 100;
|
||||||
|
long averageTime = 0;
|
||||||
|
long minTime = 10000; // 10 secs
|
||||||
|
long maxTime = 0;
|
||||||
|
for (int r = 1; r <= nRuns; r++) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
for (String name : this.fullDbCardNames) {
|
||||||
|
PaperCard card = this.cardDb.getCard(name);
|
||||||
|
assertNotNull(card);
|
||||||
|
}
|
||||||
|
long timeRun = System.currentTimeMillis() - start;
|
||||||
|
averageTime += timeRun;
|
||||||
|
if (timeRun < minTime)
|
||||||
|
minTime = timeRun;
|
||||||
|
if (timeRun > maxTime)
|
||||||
|
maxTime = timeRun;
|
||||||
|
}
|
||||||
|
System.out.println("[NEW] Total Time (in sec): " + ((double) averageTime)/ 1000);
|
||||||
|
System.out.println("[NEW] Average Time (in sec): " + ((double) averageTime / nRuns)/ 1000);
|
||||||
|
System.out.println("[NEW] Best Time (in sec): " + ((double) minTime)/ 1000);
|
||||||
|
System.out.println("[NEW] Worst Time (in sec): " + ((double) maxTime)/ 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCardFullDbNewImplementationToProfile(){
|
||||||
|
for (String name : this.fullDbCardNames) {
|
||||||
|
PaperCard card = this.cardDb.getCard(name);
|
||||||
|
assertNotNull(card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user