private void initPlanFragments() { Set<PlanFragment> allFrags = new HashSet<PlanFragment>(); for (Procedure proc : database.getProcedures()) { for (Statement stmt : proc.getStatements()) { allFrags.clear(); allFrags.addAll(stmt.getFragments()); allFrags.addAll(stmt.getMs_fragments()); for (PlanFragment frag : allFrags) { Collection<Table> tables = CatalogUtil.getReferencedTables(frag); int tableIds[] = new int[tables.size()]; int i = 0; for (Table tbl : tables) { tableIds[i++] = tbl.getRelativeIndex(); } // FOR if (frag.getReadonly()) { this.fragmentReadTables.put(Long.valueOf(frag.getId()), tableIds); } else { this.fragmentWriteTables.put(Long.valueOf(frag.getId()), tableIds); } } // FOR (frag) } // FOR (stmt) } // FOR (proc) }
@Override public void process(Pair<TransactionTrace, Integer> p) { assert (p != null); final TransactionTrace txn_trace = p.getFirst(); final int i = p.getSecond(); // Interval final int txn_weight = (use_txn_weights ? txn_trace.getWeight() : 1); final String proc_key = CatalogKey.createKey(CatalogUtil.DEFAULT_DATABASE_NAME, txn_trace.getCatalogItemName()); // Terrible Hack: Assume that we are using the SingleSitedCostModel // and that // it will return fixed values based on whether the txn is // single-partitioned or not SingleSitedCostModel singlesited_cost_model = (SingleSitedCostModel) cost_models[i]; total_interval_txns[i] += txn_weight; total_interval_queries[i] += (txn_trace.getQueryCount() * txn_weight); histogram_procs.put(proc_key, txn_weight); try { singlesited_cost_model.estimateTransactionCost(catalogContext, workload, filter, txn_trace); TransactionCacheEntry txn_entry = singlesited_cost_model.getTransactionCacheEntry(txn_trace); assert (txn_entry != null) : "No txn entry for " + txn_trace; Collection<Integer> partitions = txn_entry.getTouchedPartitions(); // If the txn runs on only one partition, then the cost is // nothing if (txn_entry.isSinglePartitioned()) { singlepartition_ctrs[i] += txn_weight; if (!partitions.isEmpty()) { assert (txn_entry.getAllTouchedPartitionsHistogram().getValueCount() == 1) : txn_entry + " says it was single-partitioned but the partition count says otherwise:\n" + txn_entry.debug(); singlepartition_with_partitions_ctrs[i] += txn_weight; } histogram_sp_procs.put(proc_key, txn_weight); // If the txn runs on multiple partitions, then the cost // is... // XXX 2010-06-28: The number of partitions that the txn // touches divided by the total number of partitions // XXX 2010-07-02: The histogram for the total number of // partitions touched by all of the queries // in the transaction. This ensures that txns with just one // multi-partition query // isn't weighted the same as a txn with many // multi-partition queries } else { assert (!partitions.isEmpty()) : "No touched partitions for " + txn_trace; if (partitions.size() == 1 && txn_entry.getExecutionPartition() != HStoreConstants.NULL_PARTITION_ID) { assert (CollectionUtil.first(partitions) != txn_entry.getExecutionPartition()) : txn_entry.debug(); exec_mismatch_ctrs[i] += txn_weight; partitions_touched[i] += txn_weight; } else { assert (partitions.size() > 1) : String.format( "%s is not marked as single-partition but it only touches one partition\n%s", txn_trace, txn_entry.debug()); } partitions_touched[i] += (partitions.size() * txn_weight); // Txns multipartition_ctrs[i] += txn_weight; histogram_mp_procs.put(proc_key, txn_weight); } Integer base_partition = txn_entry.getExecutionPartition(); if (base_partition != null) { exec_histogram[i].put(base_partition, txn_weight); } else { exec_histogram[i].put(all_partitions, txn_weight); } if (debug.val) { // && // txn_trace.getCatalogItemName().equalsIgnoreCase("DeleteCallForwarding")) // { Procedure catalog_proc = txn_trace.getCatalogItem(catalogContext.database); Map<String, Object> inner = new LinkedHashMap<String, Object>(); for (Statement catalog_stmt : catalog_proc.getStatements()) { inner.put(catalog_stmt.fullName(), CatalogUtil.getReferencedTables(catalog_stmt)); } Map<String, Object> m = new LinkedHashMap<String, Object>(); m.put(txn_trace.toString(), null); m.put("Interval", i); m.put("Single-Partition", txn_entry.isSinglePartitioned()); m.put("Base Partition", base_partition); m.put("Touched Partitions", partitions); m.put(catalog_proc.fullName(), inner); LOG.debug(StringUtil.formatMaps(m)); } // We need to keep a count of the number txns that didn't have // all of its queries estimated // completely so that we can update the access histograms down // below for entropy calculations // Note that this is at the txn level, not the query level. if (!txn_entry.isComplete()) { incomplete_txn_ctrs[i] += txn_weight; tmp_missingPartitions.clear(); tmp_missingPartitions.addAll(all_partitions); tmp_missingPartitions.removeAll(txn_entry.getTouchedPartitions()); // Update the histogram for this interval to keep track of // how many times we need to // increase the partition access histogram incomplete_txn_histogram[i].put(tmp_missingPartitions, txn_weight); if (trace.val) { Map<String, Object> m = new LinkedHashMap<String, Object>(); m.put(String.format("Marking %s as incomplete in interval #%d", txn_trace, i), null); m.put("Examined Queries", txn_entry.getExaminedQueryCount()); m.put("Total Queries", txn_entry.getTotalQueryCount()); m.put("Touched Partitions", txn_entry.getTouchedPartitions()); m.put("Missing Partitions", tmp_missingPartitions); LOG.trace(StringUtil.formatMaps(m)); } } } catch (Exception ex) { CatalogUtil.saveCatalog(catalogContext.catalog, CatalogUtil.CATALOG_FILENAME); throw new RuntimeException( "Failed to estimate cost for " + txn_trace.getCatalogItemName() + " at interval " + i, ex); } }