Mercurial Hosting > nabble
diff src/nabble/model/DailyNumber.java @ 0:7ecd1a4ef557
add content
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 21 Mar 2019 19:15:52 -0600 |
parents | |
children | 72765b66e2c3 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/nabble/model/DailyNumber.java Thu Mar 21 19:15:52 2019 -0600 @@ -0,0 +1,219 @@ +package nabble.model; + +import fschmidt.db.Listener; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + + +public final class DailyNumber { + private static final long updateFreq = 1000L*60; + private static long lastUpdate = System.currentTimeMillis(); + private static final Object lock = new Object(); + private static final List<DailyNumber> dailyNumbers = new ArrayList<DailyNumber>(); + private static boolean hasChanged = false; + + private final String field; + private int inc = 0; + + private DailyNumber(String field) { + this.field = field; + synchronized(lock) { + dailyNumbers.add(this); + } + } + + public void inc() { + synchronized(lock) { + hasChanged = true; + inc++; + if( System.currentTimeMillis() - lastUpdate >= updateFreq ) + doSave(); + } + } + + public void dec() { + synchronized(lock) { + hasChanged = true; + inc--; + if( System.currentTimeMillis() - lastUpdate >= updateFreq ) + doSave(); + } + } + + static void shutdown() { + synchronized(lock) { + doSave(); + } + } + + private static void doSave() { + if( !hasChanged ) + return; + hasChanged = false; + try { + Connection con = Db.dbGlobal().getConnection(); + try { + boolean hasInc = false; + StringBuilder buf = new StringBuilder(); + buf.append( "update daily_numbers" ); + for( DailyNumber dn : dailyNumbers ) { + if( dn.inc == 0 ) + continue; + if( !hasInc ) { + buf.append( " set " ); + hasInc = true; + } else { + buf.append( ", " ); + } + buf.append( dn.field ).append( "=" ) + .append( dn.field ).append( "+" ).append( dn.inc ); + dn.inc = 0; + } + if( !hasInc ) + return; + java.sql.Date day = new java.sql.Date(lastUpdate); + buf.append( " where day=cast(" ).append( Db.dbGlobal().arcana().quote(day) ).append(" as date)"); + Statement stmt = con.createStatement(); + int n = stmt.executeUpdate( buf.toString() ); + if( n == 0 ) { + stmt.executeUpdate( + "insert into daily_numbers (day) values (" + Db.dbGlobal().arcana().quote(day) + ")" + ); + if( stmt.executeUpdate(buf.toString()) != 1 ) + throw new RuntimeException(); + } + stmt.close(); + } finally { + con.close(); + } + } catch(SQLException e) { + throw new RuntimeException(e); + } finally { + lastUpdate = System.currentTimeMillis(); + } + } + + private static ThreadLocal<java.sql.Date> tlDay = new ThreadLocal<java.sql.Date>(); + private static ThreadLocal<Map<DailyNumber,Integer>> tlMap = new ThreadLocal<Map<DailyNumber,Integer>>(); + + public int get(Date date) { + java.sql.Date day = new java.sql.Date(date.getTime()); + if( !day.equals(tlDay.get()) ) { + Map<DailyNumber,Integer> map = new HashMap<DailyNumber,Integer>(); + try { + Connection con = Db.dbGlobal().getConnection(); + PreparedStatement stmt = con.prepareStatement( + "select * from daily_numbers where day=?" + ); + stmt.setDate(1,day); + ResultSet rs = stmt.executeQuery(); + boolean hasNumbers = rs.next(); + for( Iterator i=dailyNumbers.iterator(); i.hasNext(); ) { + DailyNumber dn = (DailyNumber)i.next(); + map.put( dn, new Integer(hasNumbers?rs.getInt(dn.field):0) ); + } + stmt.close(); + con.close(); + } catch(SQLException e) { + throw new RuntimeException(e); + } + tlDay.set(day); + tlMap.set(map); + } + Map<DailyNumber,Integer> map = tlMap.get(); + return map.get(this); + } + + public static final DailyNumber totalVisits = new DailyNumber("total_visits"); + public static final DailyNumber directVisits = new DailyNumber("direct_visits"); + public static final DailyNumber searchEngineVisits = new DailyNumber("se_visits"); + public static final DailyNumber externalVisits = new DailyNumber("ext_visits"); + public static final DailyNumber adVisits = new DailyNumber("ad_visits"); + public static final DailyNumber registrations = new DailyNumber("registrations"); + public static final DailyNumber logins = new DailyNumber("logins"); + public static final DailyNumber externalPosts = new DailyNumber("external_posts"); + public static final DailyNumber internalPosts = new DailyNumber("internal_posts"); + public static final DailyNumber replies = new DailyNumber("replies"); + public static final DailyNumber localForumPosts = new DailyNumber("local_forum_posts"); + + public static final DailyNumber forumsStarted = new DailyNumber("forums_started"); + public static final DailyNumber galleriesStarted = new DailyNumber("galleries_started"); + public static final DailyNumber newspapersStarted = new DailyNumber("newspapers_started"); + public static final DailyNumber blogsStarted = new DailyNumber("blogs_started"); + + public static final DailyNumber firstForumPosts = new DailyNumber("first_forum_posts"); + public static final DailyNumber firstGalleryPosts = new DailyNumber("first_gallery_posts"); + public static final DailyNumber firstBlogPosts = new DailyNumber("first_blog_posts"); + public static final DailyNumber firstNewspaperPosts = new DailyNumber("first_newspaper_posts"); + + public static final DailyNumber blockedSpams = new DailyNumber("blocked_spams"); + public static final DailyNumber tweaks = new DailyNumber("tweaks"); + + + static { + NodeImpl.addPostInsertListener(new Listener<NodeImpl>(){ + public void event(final NodeImpl n) { + if( ModelHome.insideImportProcedure.get() ) + return; + Db.dbGlobal().runAfterCommit(new Runnable(){public void run(){ + NodeImpl node = (NodeImpl)n.getGoodCopy(); + if( node.getKind()==Node.Kind.APP ) { + Node parent = node.getParent(); + if( parent==null || !parent.getOwner().equals(node.getOwner()) ) { + String type = node.getType(); + if (type.equals(Node.Type.GALLERY)) + DailyNumber.galleriesStarted.inc(); + else if (type.equals(Node.Type.NEWS)) + DailyNumber.newspapersStarted.inc(); + else if (type.equals(Node.Type.BLOG)) + DailyNumber.blogsStarted.inc(); + else + DailyNumber.forumsStarted.inc(); + } + return; + } + NodeImpl post = node; + if( post.isFromMailingList() ) { + DailyNumber.externalPosts.inc(); + } else { + DailyNumber.internalPosts.inc(); + if( post.getAssociatedMailingList() == null ) + DailyNumber.localForumPosts.inc(); + } + NodeImpl parent = post.getParentImpl(); + if( parent != null && parent.getKind()==Node.Kind.POST && !parent.isFromMailingList() ) + DailyNumber.replies.inc(); + + boolean isFirstPost = parent != null && parent.getKind()==Node.Kind.APP && parent.getDescendantCount() == 1; + if (isFirstPost) { + String type = parent.getType(); + if (type.equals(Node.Type.GALLERY)) + DailyNumber.firstGalleryPosts.inc(); + else if (type.equals(Node.Type.NEWS)) + DailyNumber.firstNewspaperPosts.inc(); + else if (type.equals(Node.Type.BLOG)) + DailyNumber.firstBlogPosts.inc(); + else + DailyNumber.firstForumPosts.inc(); + } + }}); + } + }); + } + + static void nop() {} + + static { + Init.dailyNumberStarted = true; + } +}