2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 2N/A * Rotate the hash by LSHIFT bits, then XOR the next word. 2N/A * hashval must be an unsigned type. 2N/A * Because qsort(3C) does not allow an argument to be passed to a comparison 2N/A * function, the variables that affect comparison must regrettably be global; 2N/A * they are protected by a global static lock, dt_qsort_lock. 2N/A * If they're both equal, then we will compare based on the weights at 2N/A * zero. If the weights at zero are equal (or if zero is not within 2N/A * the range of the linear quantization), then this will be judged a 2N/A * tie and will be resolved based on the key comparison. 2N/A * If they're both equal, then we will compare based on the weights at 2N/A * zero. If the weights at zero are equal, then this will be judged a 2N/A * tie and will be resolved based on the key comparison. 2N/A * We don't have a way of just getting the module for a 2N/A * vectored open, and it doesn't seem to be worth defining 2N/A * one. This means that use of mod() won't get true 2N/A * aggregation in the postmortem case (some modules may 2N/A * appear more than once in aggregation output). It seems 2N/A * unlikely that anyone will ever notice or care... 2N/A * First, we'll check the variable ID in the aggdesc. If it's valid, 2N/A * we'll return it. If not, we'll use the compiler-generated ID 2N/A * present as the first record. 2N/A /* Check to see if we're at the maximum size */ 2N/A /* First, allocate the new array; if we fail, we will not resize. */ 2N/A * All moved, now update hash info. 2N/A * If that failed with ENOENT, it may be because the 2N/A * CPU was unconfigured. This is okay; we'll just 2N/A * do nothing but return success. 2N/A * We're guaranteed to have an ID. 2N/A * This is filler to assure proper alignment of the 2N/A * next record; we simply ignore it. 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A * For locks (lockstat) things are int aligned, so we 2N/A * are not using the entire hash. 2N/A * We found it. Now we need to apply the aggregating 2N/A * action on the data here. 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A * If we're keeping per CPU data, apply the aggregating 2N/A * action there as well. 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A * No entry for this record -- allocate a new one. Before doing 2N/A * so, see if we should grow the hash. (If it cannot be grown, 2N/A * just add the entry to the existing hash.) 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A for (j = 0; j <
2; j++) {
2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A * If we're here, the values for the two aggregation elements are 2N/A * equal. We already know that the key layout is the same for the two 2N/A * elements; we must now compare the keys themselves as a tie-breaker. 2N/A * If we're sorting on keys, we need to scan until we find the 2N/A * last entry -- that's the representative key. (The order of 2N/A * the bundle is values followed by key to accommodate the 2N/A * default behavior of sorting by value.) If the keys are 2N/A * equal, we'll fall into the value comparison loop, below. 2N/A for (i = 0; ; i++) {
2N/A * All of the values are equal; if we're sorting on 2N/A * keys, then we're only here because the keys were 2N/A * found to be equal and these records are therefore 2N/A * equal. If we're not sorting on keys, we'll use the 2N/A * key comparison from the representative key as the 2N/A * Use the aggregation buffer size as reloaded from the kernel. 2N/A * Now query for the CPUs enabled. 2N/A * We assume that errno is already set in this case. 2N/A * First, remove this hash entry from its hash chain. 2N/A * Now remove it from the list of all hash entries. 2N/A * We're unlinked. We can safely destroy the data. 2N/A * dt_aggwalk_rval() can potentially remove the current hash 2N/A * entry; we need to load the next hash entry before calling 2N/A int (*
sfunc)(
const void *,
const void *))
2N/A * If we've been explicitly passed a sorting function, 2N/A * we'll use that -- ignoring the values of the "aggsortrev", 2N/A * "aggsortkey" and "aggsortkeypos" options. 2N/A * If the sorting position is greater than the number of aggregation 2N/A * variable IDs, we silently set it to 0. 2N/A * First we need to translate the specified aggregation variable IDs 2N/A * into a linear map that will allow us to translate an aggregation 2N/A * variable ID into its position in the specified aggvars. 2N/A * We have an aggregation variable that is present 2N/A * more than once in the array of aggregation 2N/A * variables. While it's unclear why one might want 2N/A * to do this, it's legal. To support this construct, 2N/A * we will allocate a remap that will indicate the 2N/A * position from which this aggregation variable 2N/A * should be pulled. (That is, where the remap will 2N/A * map from one position to another.) 2N/A * Given that the variable is already present, assert 2N/A * that following through the mapping and adjusting 2N/A * for the sort position yields the same aggregation 2N/A * We need to take two passes over the data to size our allocation, so 2N/A * we'll use the first pass to also fill in the zero-filled data to be 2N/A * used to properly format a zero-valued aggregation. 2N/A * We couldn't find any entries; there is nothing else to do. 2N/A * Before we sort the data, we're going to look for any holes in our 2N/A * zero-filled data. This will occur if an aggregation variable that 2N/A * we are being asked to print has not yet been assigned the result of 2N/A * any aggregating action for _any_ tuple. The issue becomes that we 2N/A * would like a zero value to be printed for all columns for this 2N/A * aggregation, but without any record description, we don't know the 2N/A * aggregating action that corresponds to the aggregation variable. To 2N/A * try to find a match, we're simply going to lookup aggregation IDs 2N/A * (which are guaranteed to be contiguous and to start from 1), looking 2N/A * for the specified aggregation variable ID. If we find a match, 2N/A * we'll use that. If we iterate over all aggregation IDs and don't 2N/A * find a match, then we must be an anonymous enabling. (Anonymous 2N/A * enablings can't currently derive either aggregation variable IDs or 2N/A * aggregation variable names given only an aggregation ID.) In this 2N/A * obscure case (anonymous enabling, multiple aggregation printa() with 2N/A * some aggregations not represented for any tuple), our defined 2N/A * behavior is that the zero will be printed in the format of the first 2N/A * aggregation variable that contains any non-zero value. 2N/A * We have our description -- now we need to 2N/A * cons up the zaggdata entry for it. 2N/A * We couldn't find this aggregation, meaning 2N/A * that we have never seen it before for any 2N/A * tuple _and_ this is an anonymous enabling. 2N/A * That is, we're in the obscure case outlined 2N/A * above. In this case, our defined behavior 2N/A * is to format the data in the format of the 2N/A * first non-zero aggregation -- of which, of 2N/A * course, we know there to be at least one 2N/A * (or nentries would have been zero). 2N/A * Now we need to allocate our zero-filled data for use for 2N/A * aggregations that don't have a value corresponding to a given key. 2N/A * If we failed to allocated some zero-filled data, we 2N/A * need to zero out the remaining dtada_data pointers 2N/A * to prevent the wrong data from being freed below. 2N/A * First, the easy bit. To maintain compatibility with 2N/A * consumers that pull the compiler-generated ID out of the 2N/A * data, we put that ID at the top of the zero-filled data. 2N/A /* LINTED - alignment */ 2N/A * Now for the more complicated part. If (and only if) this 2N/A * is an lquantize() aggregating action, zero-filled data is 2N/A * not equivalent to an empty record: we must also get the 2N/A * parameters for the lquantize(). 2N/A * The easier case here is if we actually have 2N/A * some prototype data -- in which case we 2N/A * manually dig it out of the aggregation 2N/A /* LINTED - alignment */ 2N/A * We don't have any prototype data. As a 2N/A * result, we know that we _do_ have the 2N/A * compiler-generated information. (If this 2N/A * were an anonymous enabling, all of our 2N/A * zero-filled data would have prototype data 2N/A * -- either directly or indirectly.) So as 2N/A * gross as it is, we'll grovel around in the 2N/A * compiler-generated information to find the 2N/A * lquantize() parameters. 2N/A /* LINTED - alignment */ 2N/A * Now that we've dealt with setting up our zero-filled data, we can 2N/A * allocate our sorted array, and take another pass over the data to 2N/A * We've loaded our array; now we need to sort by value to allow us 2N/A * to create bundles of like value. We're going to acquire the 2N/A * dt_qsort_lock here, and hold it across all of our subsequent 2N/A * comparison and sorting. 2N/A * Now we need to go through and create bundles. Because the number 2N/A * of bundles is bounded by the size of the sorted array, we're going 2N/A * to reuse the underlying storage. And note that "bundle" is an 2N/A * array of pointers to arrays of pointers to dt_ahashent_t -- making 2N/A * its type (regrettably) "dt_ahashent_t ***". (Regrettable because 2N/A * '*' -- like '_' and 'X' -- should never appear in triplicate in 2N/A * We have a bundle boundary. Everything from start to 2N/A * (i - 1) belongs in one bundle. 2N/A * Before we assume that this aggregation variable 2N/A * isn't present (and fall back to using the 2N/A * zero-filled data allocated earlier), check the 2N/A * remap. If we have a remapping, we'll drop it in 2N/A * here. Note that we might be remapping an 2N/A * aggregation variable that isn't present for this 2N/A * key; in this case, the aggregation data that we 2N/A * copy will point to the zeroed data. 2N/A * Now we need to re-sort based on the first value. 2N/A * We're done! Now we just need to go back over the sorted bundles, 2N/A * calling the function. 2N/A * The representative key is the last element in the bundle. 2N/A * Assert that we have one, and then set it to be the first