diff --git a/htroot/Language_p.java b/htroot/Language_p.java index ae92b28cc..a4c31ffbd 100644 --- a/htroot/Language_p.java +++ b/htroot/Language_p.java @@ -53,6 +53,7 @@ import java.io.PrintWriter; import java.net.URL; import java.util.Iterator; import java.util.Vector; +import java.util.HashMap; import de.anomic.data.listManager; import de.anomic.http.httpHeader; @@ -63,8 +64,20 @@ import de.anomic.server.serverObjects; import de.anomic.server.serverSwitch; import de.anomic.data.translator; + public class Language_p { + public static HashMap langMap(serverSwitch env) { + String[] ms = env.getConfig("htLocaleLang", "").split(","); + HashMap map = new HashMap(); + int p; + for (int i = 0; i < ms.length; i++) { + p = ms[i].indexOf("/"); + if (p > 0) map.put(ms[i].substring(0, p), ms[i].substring(p + 1)); + } + return map; + } + private static boolean copyFile(File from, File to){ if(from == null || to == null){ return false; @@ -153,20 +166,26 @@ public class Language_p { //reread language files langFiles = listManager.getDirListing(langPath); int i; - //virtuell entry + HashMap langNames = langMap(env); + String langKey, langName; + + //virtuell entry prop.put("langlist_0_file", "default"); - prop.put("langlist_0_name", "default"); - + prop.put("langlist_0_name", ((langNames.get("default") == null) ? "default" : (String) langNames.get("default"))); + for(i=0;i<= langFiles.length-1 ;i++){ if(langFiles[i].endsWith(".lng")){ //+1 because of the virtuall entry "default" at top + langKey = langFiles[i].substring(0, langFiles[i].length() -4); + langName = (String) langNames.get(langKey); prop.put("langlist_"+(i+1)+"_file", langFiles[i]); - prop.put("langlist_"+(i+1)+"_name", langFiles[i].substring(0, langFiles[i].length() -4)); + prop.put("langlist_"+(i+1)+"_name", ((langName == null) ? langKey : langName)); } } prop.put("langlist", (i+1)); - prop.put("currentlang", env.getConfig("htLocaleSelection", "default")); + langName = (String) langNames.get(env.getConfig("htLocaleSelection", "default")); + prop.put("currentlang", ((langName == null) ? "default" : langName)); return prop; } diff --git a/htroot/env/templates/header.template b/htroot/env/templates/header.template index a14ed560e..e3b58cc8a 100644 --- a/htroot/env/templates/header.template +++ b/htroot/env/templates/header.template @@ -63,6 +63,7 @@   Log   Settings   Performance +   Language   Skins diff --git a/source/de/anomic/kelondro/kelondroMap.java b/source/de/anomic/kelondro/kelondroMap.java index e7c39d6ff..437ff1b6f 100644 --- a/source/de/anomic/kelondro/kelondroMap.java +++ b/source/de/anomic/kelondro/kelondroMap.java @@ -173,9 +173,9 @@ public class kelondroMap { valuel = Long.parseLong(value); accumulator = (Long) accMap.get(accfields[i]); if (add) - accMap.put(accfields[i], new Long(accumulator.longValue() + valuel)); + accMap.put(accfields[i], new Long(accumulator.longValue() + ((long) valuel))); else - accMap.put(accfields[i], new Long(accumulator.longValue() - valuel)); + accMap.put(accfields[i], new Long(accumulator.longValue() - ((long) valuel))); } catch (NumberFormatException e) {} } } diff --git a/source/de/anomic/kelondro/kelondroTree.java b/source/de/anomic/kelondro/kelondroTree.java index 2105efe5d..a7bff903a 100644 --- a/source/de/anomic/kelondro/kelondroTree.java +++ b/source/de/anomic/kelondro/kelondroTree.java @@ -546,7 +546,7 @@ public class kelondroTree extends kelondroRecords implements Comparator { } // Associates the specified value with the specified key in this map - public byte[] put(byte[] key, byte[] value) throws IOException { + public synchronized byte[] put(byte[] key, byte[] value) throws IOException { byte[][] row = new byte[2][]; row[0] = key; row[1] = value; @@ -555,7 +555,7 @@ public class kelondroTree extends kelondroRecords implements Comparator { } // Removes the mapping for this key from this map if present (optional operation). - public byte[][] remove(byte[] key) throws IOException { + public synchronized byte[][] remove(byte[] key) throws IOException { Search search = new Search(key); if (search.found()) { Node result = search.getMatcher(); diff --git a/source/de/anomic/plasma/plasmaCrawlLURL.java b/source/de/anomic/plasma/plasmaCrawlLURL.java index fa70fc6ae..e62275d31 100644 --- a/source/de/anomic/plasma/plasmaCrawlLURL.java +++ b/source/de/anomic/plasma/plasmaCrawlLURL.java @@ -303,7 +303,7 @@ public class plasmaCrawlLURL extends plasmaURL { prop.put("table_indexed_" + c + "_showInit", (showInit) ? 1 : 0); prop.put("table_indexed_" + c + "_showInit_initiatorSeed", (initiatorSeed == null) ? dfltInit : initiatorSeed.getName()); prop.put("table_indexed_" + c + "_showExec", (showExec) ? 1 : 0); - prop.put("table_indexed_" + c + "_showExec_executorSeed", (initiatorSeed == null) ? dfltExec : executorSeed.getName()); + prop.put("table_indexed_" + c + "_showExec_executorSeed", (executorSeed == null) ? dfltExec : executorSeed.getName()); prop.put("table_indexed_" + c + "_moddate", daydate(urle.moddate())); prop.put("table_indexed_" + c + "_wordcount", urle.wordCount()); prop.put("table_indexed_" + c + "_urldescr", urle.descr()); diff --git a/source/de/anomic/plasma/plasmaWordIndexCache.java b/source/de/anomic/plasma/plasmaWordIndexCache.java index 7a766c306..dc99ca7eb 100644 --- a/source/de/anomic/plasma/plasmaWordIndexCache.java +++ b/source/de/anomic/plasma/plasmaWordIndexCache.java @@ -65,11 +65,13 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { private plasmaWordIndexInterface backend; private TreeMap cache; private kelondroMScoreCluster hashScore; - private HashMap hashDate; + private kelondroMScoreCluster hashDate; + private long startTime; private int maxWords; private serverLog log; private plasmaWordIndexAssortmentCluster assortmentCluster; - private int singletonBufferSize; //kb + private int assortmentBufferSize; //kb + private flush flushThread; // calculated constants private static String minKey, maxKey; @@ -80,7 +82,7 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { for (int i = 0; i < yacySeedDB.commonHashLength; i++) maxKey += '-'; } - public plasmaWordIndexCache(File databaseRoot, plasmaWordIndexInterface backend, int singletonbufferkb, serverLog log) { + public plasmaWordIndexCache(File databaseRoot, plasmaWordIndexInterface backend, int assortmentbufferkb, serverLog log) { // migrate#1 File oldSingletonFile = new File(databaseRoot, oldSingletonFileName); File newSingletonFile = new File(databaseRoot, newSingletonFileName); @@ -94,17 +96,21 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { File acSingletonFile = new File(assortmentClusterPath, newSingletonFileName); if ((newSingletonFile.exists()) && (!(acSingletonFile.exists()))) newSingletonFile.renameTo(acSingletonFile); + // create flushing thread + flushThread = new flush(); + // creates a new index cache // the cache has a back-end where indexes that do not fit in the cache are flushed this.databaseRoot = databaseRoot; - this.singletonBufferSize = singletonbufferkb; + this.assortmentBufferSize = assortmentbufferkb; this.cache = new TreeMap(); this.hashScore = new kelondroMScoreCluster(); - this.hashDate = new HashMap(); + this.hashDate = new kelondroMScoreCluster(); + this.startTime = System.currentTimeMillis(); this.maxWords = 10000; this.backend = backend; this.log = log; - this.assortmentCluster = new plasmaWordIndexAssortmentCluster(assortmentClusterPath, assortmentLimit, singletonBufferSize, log); + this.assortmentCluster = new plasmaWordIndexAssortmentCluster(assortmentClusterPath, assortmentLimit, assortmentBufferSize, log); // read in dump of last session try { @@ -113,8 +119,12 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { log.logError("unable to restore cache dump: " + e.getMessage()); e.printStackTrace(); } + + // start permanent flushing + flushThread.start(); } + private void dump(int waitingSeconds) throws IOException { log.logSystem("creating dump for index cache, " + cache.size() + " words (and much more urls)"); File indexDumpFile = new File(databaseRoot, indexDumpFileName); @@ -125,20 +135,17 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { long wordsPerSecond = 0, wordcount = 0, urlcount = 0; synchronized (cache) { Iterator i = cache.entrySet().iterator(); - //Iterator i = hashScore.scores(true); Map.Entry entry; String wordHash; plasmaWordIndexEntryContainer container; - long creationTime; + long updateTime; plasmaWordIndexEntry wordEntry; byte[][] row = new byte[5][]; while (i.hasNext()) { // get entries entry = (Map.Entry) i.next(); - //wordHash = (String) i.next(); wordHash = (String) entry.getKey(); - creationTime = getCreationTime(wordHash); - //container = (plasmaWordIndexEntryContainer) cache.get(wordHash); + updateTime = getUpdateTime(wordHash); container = (plasmaWordIndexEntryContainer) entry.getValue(); // put entries on stack @@ -148,7 +155,7 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { wordEntry = (plasmaWordIndexEntry) ci.next(); row[0] = wordHash.getBytes(); row[1] = kelondroRecords.long2bytes(container.size(), 4); - row[2] = kelondroRecords.long2bytes(creationTime, 8); + row[2] = kelondroRecords.long2bytes(updateTime, 8); row[3] = wordEntry.getUrlHash().getBytes(); row[4] = wordEntry.toEncodedForm(true).getBytes(); dumpStack.push(row); @@ -235,7 +242,7 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { public Iterator wordHashes(String startWordHash, boolean up) { // here we merge 3 databases into one view: // - the RAM Cache - // - the singleton File Cache + // - the assortmentCluster File Cache // - the backend if (!(up)) throw new RuntimeException("plasmaWordIndexCache.wordHashes can only count up"); return new kelondroMergeIterator( @@ -247,6 +254,49 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { true); } + private class flush extends Thread { + boolean terminate, pause; + + public flush() { + terminate = false; + pause = false; + } + + public void run() { + String nextHash; + while (!terminate) { + if (pause) { + try {this.sleep(300);} catch (InterruptedException e) {} + } else { + nextHash = (String) hashDate.getMinObject(); + if (nextHash != null) { + try { + flushFromMem(nextHash, true); + } catch (Exception e) { + log.logError("flushThread: " + e.getMessage()); + e.printStackTrace(); + } + try {this.sleep(10 + java.lang.Math.min(1000, 10 * maxWords/(cache.size() + 1)));} catch (InterruptedException e) {} + } else { + try {this.sleep(2000);} catch (InterruptedException e) {} + } + } + } + } + + public void pause() { + pause = true; + } + + public void proceed() { + pause = false; + } + + public void terminate() { + terminate = true; + } + } + private int flushFromMem(String key, boolean reintegrate) { // this method flushes indexes out from the ram to the disc. // at first we check the singleton database and act accordingly @@ -261,12 +311,12 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { // get the container container = (plasmaWordIndexEntryContainer) cache.get(key); if (container == null) return 0; // flushing of nonexisting key - time = getCreationTime(key); + time = getUpdateTime(key); // remove it from the cache cache.remove(key); hashScore.deleteScore(key); - hashDate.remove(key); + hashDate.deleteScore(key); } // now decide where to flush that container @@ -296,7 +346,7 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { synchronized (cache) { cache.put(key, container); hashScore.setScore(key, container.size()); - hashDate.put(key, new Long(time)); + hashDate.setScore(key, intTime(time)); } return -flushedFromAssortment.size(); } else { @@ -306,6 +356,14 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { } } + private int intTime(long longTime) { + return (int) ((longTime - startTime) / 1000); + } + + private long longTime(int intTime) { + return ((long) intTime) * ((long) 1000) + startTime; + } + private boolean flushFromAssortmentCluster(String key) { // this should only be called if the singleton shall be deleted or returned in an index entity plasmaWordIndexEntryContainer container = assortmentCluster.removeFromAll(key); @@ -319,19 +377,9 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { } private synchronized int flushFromMemToLimit() { - if ((hashScore.size() == 0) && (cache.size() == 0)) { - serverLog.logDebug("PLASMA INDEXING", "flushToLimit: called but cache is empty"); - return 0; - } - if ((hashScore.size() == 0) && (cache.size() != 0)) { - serverLog.logError("PLASMA INDEXING", "flushToLimit: hashScore.size=0 but cache.size=" + cache.size()); - return 0; - } - if ((hashScore.size() != 0) && (cache.size() == 0)) { - serverLog.logError("PLASMA INDEXING", "flushToLimit: hashScore.size=" + hashScore.size() + " but cache.size=0"); - return 0; - } + if ((hashScore.size() == 0) || (cache.size() == 0)) return 0; + flushThread.pause(); int count = 0; //serverLog.logDebug("PLASMA INDEXING", "flushSpecific: hashScore.size=" + hashScore.size() + ", cache.size=" + cache.size()); synchronized (hashScore) { @@ -345,7 +393,7 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { while (i.hasNext()) { // get the entry properties key = (String) i.next(); - createTime = (Long) hashDate.get(key); + createTime = new Long(longTime(hashDate.getScore(key))); count = hashScore.getScore(key); // put it into a specific ohl @@ -396,7 +444,10 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { // stop flushing if cache is shrinked enough // avoid as possible to flush high-scores - if (cache.size() < this.maxWords - 100) return count; + if (cache.size() < this.maxWords - 100) { + flushThread.proceed(); + return count; + } // flush high-scores for (int cluster = java.lang.Math.min(clusterCandidate.length, ramcacheLimit); cluster > assortmentLimit; cluster--) { @@ -411,43 +462,60 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { candidateCounter += cluster; log.logDebug("flushed high-cluster below limit #" + cluster + ", key=" + key + ", count=" + count + ", cachesize=" + cache.size()); } - if (cache.size() < this.maxWords - 100) return count; + if (cache.size() < this.maxWords - 100) { + flushThread.proceed(); + return count; + } } } } + flushThread.proceed(); return count; } public plasmaWordIndexEntity getIndex(String wordHash, boolean deleteIfEmpty) { + flushThread.pause(); flushFromMem(wordHash, false); flushFromAssortmentCluster(wordHash); + flushThread.proceed(); return backend.getIndex(wordHash, deleteIfEmpty); } - public long getCreationTime(String wordHash) { - Long time = (Long) hashDate.get(wordHash); + public long getUpdateTime(String wordHash) { + plasmaWordIndexEntryContainer entries = (plasmaWordIndexEntryContainer) cache.get(wordHash); + if (entries == null) return 0; + return entries.updated(); + /* + Long time = new Long(longTime(hashDate.getScore(wordHash))); if (time == null) return 0; return time.longValue(); + */ } public void deleteIndex(String wordHash) { + flushThread.pause(); synchronized (cache) { cache.remove(wordHash); hashScore.deleteScore(wordHash); - hashDate.remove(wordHash); + hashDate.deleteScore(wordHash); } assortmentCluster.removeFromAll(wordHash); backend.deleteIndex(wordHash); + flushThread.proceed(); } public synchronized int removeEntries(String wordHash, String[] urlHashes, boolean deleteComplete) { + flushThread.pause(); flushFromMem(wordHash, false); flushFromAssortmentCluster(wordHash); - return backend.removeEntries(wordHash, urlHashes, deleteComplete); + int removed = backend.removeEntries(wordHash, urlHashes, deleteComplete); + flushThread.proceed(); + return removed; } public synchronized int addEntries(plasmaWordIndexEntryContainer container, long updateTime) { + flushThread.pause(); //serverLog.logDebug("PLASMA INDEXING", "addEntryToIndexMem: cache.size=" + cache.size() + "; hashScore.size=" + hashScore.size()); if (cache.size() >= this.maxWords) flushFromMemToLimit(); //if (flushc > 0) serverLog.logDebug("PLASMA INDEXING", "addEntryToIndexMem - flushed " + flushc + " entries"); @@ -462,10 +530,11 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { if (added > 0) { cache.put(wordHash, entries); hashScore.addScore(wordHash, added); - hashDate.put(wordHash, new Long(updateTime)); + hashDate.setScore(wordHash, intTime(updateTime)); } } //System.out.println("DEBUG: cache = " + cache.toString()); + flushThread.proceed(); return added; } @@ -475,11 +544,17 @@ public final class plasmaWordIndexCache implements plasmaWordIndexInterface { if (entries.add(new plasmaWordIndexEntry[]{newEntry}, updateTime) > 0) { cache.put(wordHash, entries); hashScore.incScore(wordHash); - hashDate.put(wordHash, new Long(updateTime)); + hashDate.setScore(wordHash, intTime(updateTime)); } + flushThread.proceed(); } public void close(int waitingSeconds) { + // stop permanent flushing + flushThread.terminate(); + try {flushThread.join(5000);} catch (InterruptedException e) {} + + // close cluster assortmentCluster.close(); try { dump(waitingSeconds); diff --git a/source/de/anomic/plasma/plasmaWordIndexClassicDB.java b/source/de/anomic/plasma/plasmaWordIndexClassicDB.java index 14782905f..482572360 100644 --- a/source/de/anomic/plasma/plasmaWordIndexClassicDB.java +++ b/source/de/anomic/plasma/plasmaWordIndexClassicDB.java @@ -187,7 +187,7 @@ public class plasmaWordIndexClassicDB implements plasmaWordIndexInterface { } } - public long getCreationTime(String wordHash) { + public long getUpdateTime(String wordHash) { File f = plasmaWordIndexEntity.wordHash2path(databaseRoot, wordHash); if (f.exists()) return f.lastModified(); else return -1; } diff --git a/source/de/anomic/plasma/plasmaWordIndexInterface.java b/source/de/anomic/plasma/plasmaWordIndexInterface.java index 218c7b58e..ef583b948 100644 --- a/source/de/anomic/plasma/plasmaWordIndexInterface.java +++ b/source/de/anomic/plasma/plasmaWordIndexInterface.java @@ -51,7 +51,7 @@ public interface plasmaWordIndexInterface { public Iterator wordHashes(String startWordHash, boolean up); public plasmaWordIndexEntity getIndex(String wordHash, boolean deleteIfEmpty); - public long getCreationTime(String wordHash); + public long getUpdateTime(String wordHash); public void deleteIndex(String wordHash); public int removeEntries(String wordHash, String[] urlHashes, boolean deleteComplete);