Docker and Locales

Since I rebuilt my server I have been seeing issues where my use of the transcode-video docker image would consistently fail to complete the encoding process with this error.

transcode-video: invalid byte sequence in US-ASCII

The linked post led me to the solution - I needed to update the Dockerfile for my version of the image to include additional commands to configure the locale. This was a pretty easy addition as I already was using my own to customise a couple of things. I do not know why the appeared, but all I really care about is that it is working again now.

FROM ntodd/video-transcoding
  
# Configure locale
RUN locale-gen en_GB.UTF-8
ENV LANG en_GB.UTF-8
ENV LANGUAGE en_GB:en
ENV LC_ALL en_GB.UTF-8


Plex DVR on Docker with the Official Xbox One Digital TV Tuner

In the last part of this series we got the Official Xbox One TV Tuner working successfully with Plex on a beta version of Fedora 28.

Last weekend one part of the RAID-1 boot drive array I used for my media server failed, so I took the opportunity to give Fedora 28 a shot as my boot OS with the replacement drive as opposed to imediately repairing the RAID. If this didn’t work out I can still swap some drives around and let the RAID resync. This may still happen, as Fedora is not offically supported on the HP Microserver I run, so I miss out on some of the agents used by the Integrated Lights-Out (iLO) server management interface to report back machine metrics.

As part of this switch I am re-evaluating what I can use Docker for, and so have OS distribution agnostic, scripted, services. Even if I do choose to switch back to CentOS this will not be a waste as there were some software packages which I was already compiling from source due to a lack of availability in CentOS repositories. When Ubuntu move to the 4.16 kernel I will likely switch again, but should have an easier time as I can re-use the configured Docker containers I have already scripted.

So it is now time to get Plex working on Docker with this tuner.

» Continue reading


Plex DVR with the Official Xbox One Digital TV Tuner - The Direct (and working!) Approach

With the recent release of version 4.16 of the linux kernel, the drivers needed to use the Xbox One Tuner are now distributed with the kernel.

At the time of writing, the only mainstream distribution using this version of the kernel is the Fedora 28 beta (due for mainstream release early May).

With this driver now part of the kernel, Plex appears to recognise the tuner as a community supported tuner and functions correctly using it directly. We still need to download and install the “dvb-demod-mn88472-02.fw” firmware file however as without this, while the tuner will be recognised in Plex, scanning for channels will always return zero results.

» Continue reading


Performance of the Java 8 Date APIs

At the weekend I was skimming over the parts of the OCA exam book which are new for Java 8, and the comparison on working with the new java.time APIs versus the previous java.util offerings got me thinking about performance. Recently I had been looking at a bit of code which was creating objects based on an object loaded from a database table with the fields shown below.

    private java.util.Date date;
    private int startHour;
    private int startMinute;
    private int endHour;
    private int endMinute

The date in this object is set to midnight time. Based on this object the code was then making two java.util.Date objects, one for each time on the date. This requires a trip in to a Calendar object to set the time fields, then converting back to a Date. This appeared to be quite an expensive operation when we were executing it tens of thousands of times during the process of a calculation.

For a test, I wrote a simple program which created an object representing today’s date, and then created 20,000 objects based on this including a time. These steps were performed for both the java.time and java.util approaches.


import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class DateTest {
    
    private static final int ITERATIONS = 20000;
    private final List<Integer> hours;
    private final List<Integer> minutes;
    private final Date midnightToday;
    private final LocalDate today;
    
    public DateTest() {
        /* Initialise lists */
        this.hours = IntStream.range(0, 23).boxed().collect(Collectors.toList());
        this.minutes = IntStream.range(0, 59).boxed().collect(Collectors.toList());
        
        /* Initialise today with the old approach */
        Date date = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        this.midnightToday = cal.getTime();
        
        /* Initialise today with the new approach */
        this.today = LocalDate.now();
    }
    
    
    public void checkNewApproach() {

        List<LocalDateTime> createdObjects = new ArrayList<>();

        while (createdObjects.size() < ITERATIONS) {
            for (int hour : hours) {
                for (int minute : minutes) {
                    if (createdObjects.size() < ITERATIONS) {
                        /* Create the object and add to our list. */
                        createdObjects.add(LocalTime.of(hour, minute).atDate(today));
                    }
                }
            }
        }
    }
    
    public void checkOldApproachDate() {

        List<Date> createdObjects = new ArrayList<>();

        while (createdObjects.size() < ITERATIONS) {
            for (int hour : hours) {
                for (int minute : minutes) {
                    if (createdObjects.size() < ITERATIONS) {
                        /* Create the object */

                        Calendar cal = Calendar.getInstance();
                        cal.setTime(midnightToday);
                        cal.set(Calendar.HOUR, hour);
                        cal.set(Calendar.MINUTE, minute);

                        createdObjects.add(cal.getTime());
                    }
                }
            }
        }
    }
    
    
    public static void main(String[] args) {
        
        /* Create */
        DateTest testObj = new DateTest();
        
        /* Test the new approach */
        long newStartTime = System.currentTimeMillis();    
        testObj.checkNewApproach();
        long newEndTime = System.currentTimeMillis();
        
        /* Test the old approach */
        long oldStartTime = System.currentTimeMillis();
        testObj.checkOldApproachDate();
        long oldEndTime = System.currentTimeMillis();
        
        /* Show the results */
        
        System.out.println(String.format(
                "\t%s\t%s", 
                (newEndTime - newStartTime), 
                (oldEndTime - oldStartTime))); 
    }

}


I compiled the code and ran the test 10 times, just to rule out any blips in system performance.

javac DateTest.java
for i in {1..10}; do echo $i $(java -cp . DateTest); sleep 2s; done

It is a crude test, but the results were quite surprising.

Run java.time (ms) java.util (ms)
1 7 104
2 7 104
3 11 126
4 10 123
5 13 135
6 12 142
7 16 299
8 10 157
9 10 125
10 8 100

I had expected some performance improvement, but not such a large one. I have no intention of getting into the “why” of the performance improvement, but it does look promising for future developments.