Send current state instead of patch (difference)

This commit is contained in:
Ivan Chirkov
2015-02-02 03:00:28 +01:00
parent bd4f8f3c28
commit d7260f3f2d
6 changed files with 35 additions and 281 deletions
@@ -19,7 +19,6 @@ import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.featureStatistics.FeatureUsageTrackerImpl;
import com.intellij.internal.statistic.beans.ConvertUsagesUtil;
import com.intellij.internal.statistic.beans.GroupDescriptor;
import com.intellij.internal.statistic.beans.PatchedUsage;
import com.intellij.internal.statistic.beans.UsageDescriptor;
import com.intellij.internal.statistic.connect.RemotelyConfigurableStatisticsService;
import com.intellij.internal.statistic.connect.StatisticsConnectionService;
@@ -29,18 +28,15 @@ import com.intellij.internal.statistic.persistence.SentUsagesPersistence;
import com.intellij.internal.statistic.persistence.UsageStatisticsPersistenceComponent;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.KeyedExtensionCollector;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.util.Function;
import com.intellij.util.Time;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
public class StatisticsUploadAssistant {
private static final Logger LOG = Logger.getInstance(StatisticsUploadAssistant.class);
@@ -73,150 +69,31 @@ public class StatisticsUploadAssistant {
}
public String getData(@NotNull Set<String> disabledGroups) {
return getStringPatch(disabledGroups);
return getDataString(disabledGroups);
}
public static void persistSentPatch(@NotNull String patchStr) {
persistSentPatch(patchStr, UsageStatisticsPersistenceComponent.getInstance());
}
public static void persistSentPatch(@NotNull String patchStr, @NotNull SentUsagesPersistence persistenceComponent) {
Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages = mapToPatchedUsagesMap(ConvertUsagesUtil.convertString(patchStr));
if (!patchedUsages.isEmpty()) {
persistenceComponent.persistPatch(patchedUsages);
}
public static void updateSentTime() {
UsageStatisticsPersistenceComponent.getInstance().setSentTime(System.currentTimeMillis());
}
@NotNull
public static String getStringPatch(@NotNull Set<String> disabledGroups) {
return getStringPatch(disabledGroups, UsageStatisticsPersistenceComponent.getInstance(), 0);
public static String getDataString(@NotNull Set<String> disabledGroups) {
return getDataString(disabledGroups, 0);
}
@NotNull
public static String getStringPatch(@NotNull Set<String> disabledGroups,
@NotNull SentUsagesPersistence usagesPersistence,
int maxSize) {
return getStringPatch(getPatchedUsages(disabledGroups, usagesPersistence), maxSize);
public static String getDataString(@NotNull Set<String> disabledGroups,
int maxSize) {
return getDataString(getAllUsages(disabledGroups), maxSize);
}
public static <T extends UsageDescriptor> String getStringPatch(@NotNull Map<GroupDescriptor, Set<T>> patchedUsages, int maxSize) {
if (patchedUsages.isEmpty()) {
public static <T extends UsageDescriptor> String getDataString(@NotNull Map<GroupDescriptor, Set<T>> usages, int maxSize) {
if (usages.isEmpty()) {
return "";
}
String patchStr = ConvertUsagesUtil.convertUsages(patchedUsages);
return maxSize > 0 && patchStr.getBytes(CharsetToolkit.UTF8_CHARSET).length > maxSize ? ConvertUsagesUtil.cutPatchString(patchStr, maxSize) : patchStr;
}
@NotNull
public static Map<GroupDescriptor, Set<PatchedUsage>> getPatchedUsages(@NotNull Set<String> disabledGroups,
@NotNull SentUsagesPersistence usagesPersistence) {
Map<GroupDescriptor, Set<PatchedUsage>> usages = new LinkedHashMap<GroupDescriptor, Set<PatchedUsage>>();
Map<GroupDescriptor, Set<UsageDescriptor>> allUsages = getAllUsages(disabledGroups);
Map<GroupDescriptor, Set<UsageDescriptor>> sentUsages = filterDisabled(disabledGroups, usagesPersistence.getSentUsages());
usages.putAll(getPatchedUsages(allUsages, sentUsages));
return usages;
}
@NotNull
private static Map<GroupDescriptor, Set<UsageDescriptor>> filterDisabled(@NotNull Set<String> disabledGroups, @NotNull Map<GroupDescriptor, Set<UsageDescriptor>> usages) {
Map<GroupDescriptor, Set<UsageDescriptor>> filtered = new LinkedHashMap<GroupDescriptor, Set<UsageDescriptor>>();
for (Map.Entry<GroupDescriptor, Set<UsageDescriptor>> usage : usages.entrySet()) {
if (!disabledGroups.contains(usage.getKey().getId())) {
filtered.put(usage.getKey(), usage.getValue());
}
}
return filtered;
}
@NotNull
public static Map<GroupDescriptor, Set<PatchedUsage>> getPatchedUsages(@NotNull final Map<GroupDescriptor, Set<UsageDescriptor>> allUsages,
@NotNull SentUsagesPersistence usagesPersistence) {
return getPatchedUsages(allUsages, usagesPersistence.getSentUsages());
}
@NotNull
public static Map<GroupDescriptor, Set<PatchedUsage>> getPatchedUsages(@NotNull Map<GroupDescriptor, Set<UsageDescriptor>> allUsages,
Map<GroupDescriptor, Set<UsageDescriptor>> sentUsageMap) {
Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages = mapToPatchedUsagesMap(allUsages);
for (Map.Entry<GroupDescriptor, Set<UsageDescriptor>> sentUsageEntry : sentUsageMap.entrySet()) {
final GroupDescriptor sentUsageGroupDescriptor = sentUsageEntry.getKey();
final Set<UsageDescriptor> sentUsages = sentUsageEntry.getValue();
for (UsageDescriptor sentUsage : sentUsages) {
final PatchedUsage descriptor = findDescriptor(patchedUsages, Pair.create(sentUsageGroupDescriptor, sentUsage.getKey()));
if (descriptor == null) {
if (!patchedUsages.containsKey(sentUsageGroupDescriptor)) {
patchedUsages.put(sentUsageGroupDescriptor, new LinkedHashSet<PatchedUsage>());
}
patchedUsages.get(sentUsageGroupDescriptor).add(new PatchedUsage(sentUsage.getKey(), -sentUsage.getValue()));
}
else {
descriptor.subValue(sentUsage.getValue());
}
}
}
return packCollection(patchedUsages, new Condition<PatchedUsage>() {
@Override
public boolean value(PatchedUsage patchedUsage) {
return patchedUsage.getDelta() != 0;
}
});
}
private static Map<GroupDescriptor, Set<PatchedUsage>> mapToPatchedUsagesMap(@NotNull Map<GroupDescriptor, Set<UsageDescriptor>> allUsages) {
Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages = new LinkedHashMap<GroupDescriptor, Set<PatchedUsage>>();
for (Map.Entry<GroupDescriptor, Set<UsageDescriptor>> entry : allUsages.entrySet()) {
patchedUsages.put(entry.getKey(), new THashSet<PatchedUsage>(ContainerUtil.map2Set(entry.getValue(), new Function<UsageDescriptor, PatchedUsage>() {
@Override
public PatchedUsage fun(UsageDescriptor usageDescriptor) {
return new PatchedUsage(usageDescriptor);
}
})));
}
return patchedUsages;
}
@NotNull
private static Map<GroupDescriptor, Set<PatchedUsage>> packCollection(@NotNull Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages, Condition<PatchedUsage> condition) {
Map<GroupDescriptor, Set<PatchedUsage>> result = new LinkedHashMap<GroupDescriptor, Set<PatchedUsage>>();
for (GroupDescriptor descriptor : patchedUsages.keySet()) {
Set<PatchedUsage> usages = packCollection(patchedUsages.get(descriptor), condition);
if (!usages.isEmpty()) {
result.put(descriptor, usages);
}
}
return result;
}
@NotNull
private static <T> Set<T> packCollection(@NotNull Collection<T> set, @NotNull Condition<T> condition) {
final Set<T> result = new LinkedHashSet<T>();
for (T t : set) {
if (condition.value(t)) {
result.add(t);
}
}
return result;
}
@Nullable
public static <T extends UsageDescriptor> T findDescriptor(@NotNull Map<GroupDescriptor, Set<T>> descriptors,
@NotNull final Pair<GroupDescriptor, String> id) {
final Set<T> usages = descriptors.get(id.getFirst());
if (usages == null) {
return null;
}
return ContainerUtil.find(usages, new Condition<T>() {
@Override
public boolean value(T t) {
return id.getSecond().equals(t.getKey());
}
});
String dataStr = ConvertUsagesUtil.convertUsages(usages);
return maxSize > 0 && dataStr.getBytes(CharsetToolkit.UTF8_CHARSET).length > maxSize ? ConvertUsagesUtil.cutDataString(dataStr, maxSize) : dataStr;
}
@NotNull
@@ -15,6 +15,7 @@
*/
package com.intellij.internal.statistic.beans;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@@ -40,10 +41,13 @@ public class ConvertUsagesUtil {
StringBuffer buffer = new StringBuffer();
for (Map.Entry<GroupDescriptor, Set<T>> entry : sortedMap.entrySet()) {
buffer.append(entry.getKey().getId());
buffer.append(GROUP_SEPARATOR);
buffer.append(convertValueMap(entry.getValue()));
buffer.append(GROUPS_SEPARATOR);
String value = convertValueMap(entry.getValue());
if (!StringUtil.isEmptyOrSpaces(value)) {
buffer.append(entry.getKey().getId());
buffer.append(GROUP_SEPARATOR);
buffer.append(value);
buffer.append(GROUPS_SEPARATOR);
}
}
return buffer.toString();
@@ -52,20 +56,25 @@ public class ConvertUsagesUtil {
//@NotNull
public static String convertValueMap(Set<? extends UsageDescriptor> descriptors) {
assert descriptors != null;
if (descriptors.isEmpty()) return "";
final StringBuffer buffer = new StringBuffer();
for (UsageDescriptor usageDescriptor : descriptors) {
buffer.append(usageDescriptor.getKey());
buffer.append("=");
buffer.append(usageDescriptor.getValue());
buffer.append(GROUP_VALUE_SEPARATOR);
int value = usageDescriptor.getValue();
if (value != 0) {
buffer.append(usageDescriptor.getKey());
buffer.append("=");
buffer.append(value);
buffer.append(GROUP_VALUE_SEPARATOR);
}
}
if (buffer.length() == 0) return "";
buffer.deleteCharAt(buffer.length() - 1);
return buffer.toString();
}
//@NotNull
public static String cutPatchString(String patchStr, int maxSize) {
public static String cutDataString(String patchStr, int maxSize) {
assert patchStr != null;
for (int i = maxSize - 1; i >= 0; i--) {
final char c = patchStr.charAt(i);
@@ -46,7 +46,7 @@ public class RemotelyConfigurableStatisticsService implements StatisticsService
try {
sender.send(serviceUrl, content);
StatisticsUploadAssistant.persistSentPatch(content);
StatisticsUploadAssistant.updateSentTime();
return new StatisticsResult(StatisticsResult.ResultCode.SEND, content);
}
@@ -16,12 +16,8 @@
package com.intellij.internal.statistic.persistence;
import com.intellij.internal.statistic.StatisticsUploadAssistant;
import com.intellij.internal.statistic.beans.GroupDescriptor;
import com.intellij.internal.statistic.beans.PatchedUsage;
import com.intellij.internal.statistic.beans.UsageDescriptor;
import com.intellij.openapi.util.Pair;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.hash.HashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -57,26 +53,6 @@ public class BasicSentUsagesPersistenceComponent extends SentUsagesPersistence {
mySentTime = time;
}
public void persistPatch(@NotNull Map<GroupDescriptor, Set<PatchedUsage>> patchedDescriptorMap) {
for (Map.Entry<GroupDescriptor, Set<PatchedUsage>> entry : patchedDescriptorMap.entrySet()) {
final GroupDescriptor groupDescriptor = entry.getKey();
for (PatchedUsage patchedUsage : entry.getValue()) {
UsageDescriptor usageDescriptor = StatisticsUploadAssistant.findDescriptor(mySentDescriptors, Pair.create(groupDescriptor, patchedUsage.getKey()));
if (usageDescriptor != null) {
usageDescriptor.setValue(usageDescriptor.getValue() + patchedUsage.getDelta());
} else {
if (!mySentDescriptors.containsKey(groupDescriptor)) {
mySentDescriptors.put(groupDescriptor, new HashSet<UsageDescriptor>());
}
mySentDescriptors.get(groupDescriptor).add(new UsageDescriptor(patchedUsage.getKey(), patchedUsage.getValue()));
}
}
}
setSentTime(System.currentTimeMillis());
}
@NotNull
public Map<GroupDescriptor, Set<UsageDescriptor>> getSentUsages () {
return mySentDescriptors;
@@ -17,7 +17,6 @@
package com.intellij.internal.statistic.persistence;
import com.intellij.internal.statistic.beans.GroupDescriptor;
import com.intellij.internal.statistic.beans.PatchedUsage;
import com.intellij.internal.statistic.beans.UsageDescriptor;
import org.jetbrains.annotations.NotNull;
@@ -26,8 +25,6 @@ import java.util.Set;
public abstract class SentUsagesPersistence {
public abstract void persistPatch(@NotNull Map<GroupDescriptor, Set<PatchedUsage>> patchedDescriptors);
@NotNull
public abstract Map<GroupDescriptor, Set<UsageDescriptor>> getSentUsages();
@@ -1,12 +1,9 @@
package com.intellij.usagesStatistics;
import com.intellij.internal.statistic.StatisticsUploadAssistant;
import com.intellij.internal.statistic.beans.ConvertUsagesUtil;
import com.intellij.internal.statistic.beans.GroupDescriptor;
import com.intellij.internal.statistic.beans.PatchedUsage;
import com.intellij.internal.statistic.beans.UsageDescriptor;
import com.intellij.internal.statistic.persistence.BasicSentUsagesPersistenceComponent;
import com.intellij.internal.statistic.persistence.SentUsagesPersistence;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.hash.HashMap;
import com.intellij.util.containers.hash.LinkedHashMap;
@@ -30,75 +27,6 @@ public class StatisticsUploadAssistantTest extends TestCase {
super.tearDown();
}
public void testCreateNewPatch() {
final Map<GroupDescriptor, Set<UsageDescriptor>> all = createDescriptors("g:a1:1", "g:a2:2", "g:a3:3");
final Map<GroupDescriptor, Set<UsageDescriptor>> sent = new HashMap<GroupDescriptor, Set<UsageDescriptor>>();
final Map<GroupDescriptor, Set<PatchedUsage>> patched = StatisticsUploadAssistant.getPatchedUsages(all, sent);
assertMapEquals(patched, createDescriptors("g:a1:1", "g:a2:2", "g:a3:3"));
}
public void testEmptyPatchs() {
final Map<GroupDescriptor, Set<UsageDescriptor>> all = new HashMap<GroupDescriptor, Set<UsageDescriptor>>();
final Map<GroupDescriptor, Set<UsageDescriptor>> sent = new HashMap<GroupDescriptor, Set<UsageDescriptor>>();
assertEquals(StatisticsUploadAssistant.getPatchedUsages(all, sent).size(), 0);
}
public void testCreateEmptyPatch() {
final Map<GroupDescriptor, Set<UsageDescriptor>> all = createDescriptors("g:a1:1", "g:a2:2", "g:a3:3", "g2:a1:1", "g2:a2:2", "g2:a3:3");
final Map<GroupDescriptor, Set<UsageDescriptor>> sent = createDescriptors("g:a1:1", "g:a2:2", "g:a3:3", "g2:a1:1", "g2:a2:2", "g2:a3:3");
assertEquals(StatisticsUploadAssistant.getPatchedUsages(all, sent).size(), 0);
}
public void testCreatePatchEmptyAll() {
final Map<GroupDescriptor, Set<UsageDescriptor>> all = new HashMap<GroupDescriptor, Set<UsageDescriptor>>();
final Map<GroupDescriptor, Set<UsageDescriptor>> sent = createDescriptors("g:a1:1", "g:a2:2", "g2:a1:1", "g2:a2:2", "g2:a3:3");
final Map<GroupDescriptor, Set<PatchedUsage>> patched = StatisticsUploadAssistant.getPatchedUsages(all, sent);
assertMapEquals(patched, createDescriptors("g:a1:-1", "g2:a2:-2", "g2:a3:-3", "g:a2:-2", "g2:a1:-1"));
}
public void testCreatePatchMerged() {
final Map<GroupDescriptor, Set<UsageDescriptor>> all = createDescriptors("g:a1:100", "g:a2:2", "g2:a1:0", "g2:a2:1");
final Map<GroupDescriptor, Set<UsageDescriptor>> sent = createDescriptors("g:a1:2", "g:a2:100", "g2:a1:1", "g2:a2:1", "g2:a3:3");
final Map<GroupDescriptor, Set<PatchedUsage>> patched = StatisticsUploadAssistant.getPatchedUsages(all, sent);
assertMapEquals(patched, createDescriptors("g:a1:98", "g:a2:-98", "g2:a1:-1", "g2:a3:-3"));
}
public void testPersistSentPatch() {
final Map<GroupDescriptor, Set<UsageDescriptor>> allUsages = createDescriptors("g:a1:-1", "g2:a2:-2", "g2:a3:-3", "g:a2:-2", "g2:a1:-1", "g3:a1:13");
final SentUsagesPersistence usagesPersistence = new BasicSentUsagesPersistenceComponent();
Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence);
String result = StatisticsUploadAssistant.getStringPatch(patchedUsages, 500);
StatisticsUploadAssistant.persistSentPatch(result, usagesPersistence);
assertMapEquals(ConvertUsagesUtil.convertString(result), ConvertUsagesUtil.convertString("g:a2=-2,a1=-1;g2:a3=-3,a2=-2,a1=-1;g3:a1=13;"));
patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence);
result = StatisticsUploadAssistant.getStringPatch(patchedUsages, 500);
StatisticsUploadAssistant.persistSentPatch(result, usagesPersistence);
assertEquals("sent usages must be persisted", result.length(), 0);
assertEquals(allUsages.size(), usagesPersistence.getSentUsages().size());
}
public void testConvertUsages() {
final Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages = StatisticsUploadAssistant
.getPatchedUsages(createDescriptors("g:a1:-1", "g2:a2:-2", "g2:a3:-3", "g:a2:-2", "g2:a1:-1", "g3:a1:13"),
new HashMap<GroupDescriptor, Set<UsageDescriptor>>());
final String result = ConvertUsagesUtil.convertUsages(patchedUsages);
final Map<GroupDescriptor, Set<UsageDescriptor>> convertedUsages = ConvertUsagesUtil.convertString(result);
assertMapEquals(patchedUsages, convertedUsages);
}
public void testConvertUsagesWithPriority() {
final Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages = new HashMap<GroupDescriptor, Set<PatchedUsage>>();
@@ -160,39 +88,6 @@ public class StatisticsUploadAssistantTest extends TestCase {
assertMapEquals(patchedUsages, ConvertUsagesUtil.convertString(veryLongGroupId + ":k1=1;g1:k1=1,k2=2;"));
}
public void testPersistSentPatchWithRestrictedSize() {
int size = 15;
final Map<GroupDescriptor, Set<UsageDescriptor>> allUsages = createDescriptors("g:a1:-1", "g2:a2:-2", "g2:a3:-3", "g:a2:-2", "g3:a1:-1", "g3:a2:13");
final SentUsagesPersistence usagesPersistence = new BasicSentUsagesPersistenceComponent();
Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence);
String first = StatisticsUploadAssistant.getStringPatch(patchedUsages, size);
StatisticsUploadAssistant.persistSentPatch(first, usagesPersistence);
assertTrue(first.length() <= size);
assertMapEquals(ConvertUsagesUtil.convertString(first), ConvertUsagesUtil.convertString("g:a1=-1,a2=-2"));
patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence);
String second = StatisticsUploadAssistant.getStringPatch(patchedUsages, size);
StatisticsUploadAssistant.persistSentPatch(second, usagesPersistence);
assertTrue(second.length() <= size);
assertFalse(second.contains(first));
assertMapEquals(ConvertUsagesUtil.convertString(second), ConvertUsagesUtil.convertString("g2:a2=-2,a3=-3"));
patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence);
String third = StatisticsUploadAssistant.getStringPatch(patchedUsages, size);
StatisticsUploadAssistant.persistSentPatch(third, usagesPersistence);
assertTrue(third.length() <= size);
assertFalse(third.contains(first));
assertFalse(third.contains(second));
assertMapEquals(ConvertUsagesUtil.convertString(third), ConvertUsagesUtil.convertString("g3:a1=-1,a2=13"));
patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence);
assertEquals(patchedUsages.size(), 0);
assertEquals(allUsages.size(), usagesPersistence.getSentUsages().size());
}
private static <T extends UsageDescriptor> void assertMapEquals(@NotNull Map<GroupDescriptor, Set<T>> expected, @NotNull Map<GroupDescriptor, Set<UsageDescriptor>> actual) {
assertEquals(expected.size(), actual.size());