Commit 18e486f1 authored by Geoff Simmons's avatar Geoff Simmons

Initial commit, passes first test for binary log reads.

parents
See LICENSE for details.
Copyright (c) 2018 UPLEX Nils Goroll Systemoptimierung
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
WORK IN PROGRESS
/*-
* Copyright (c) 2018 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "log.h"
#include "_cgo_export.h"
static int
dispatch_wrapped(struct VSL_data *vsl, struct VSL_transaction * const trans[],
void *priv)
{
return (publish((void *)trans, priv));
}
int
dispatch(struct VSLQ *vslq, int n)
{
return VSLQ_Dispatch(vslq, dispatch_wrapped, (void *)&n);
}
This diff is collapsed.
/*-
* Copyright (c) 2018 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LOG_H_INCLUDED
#define _LOG_H_INCLUDED
#include <stdio.h>
#include <vapi/vsl.h>
int dispatch(struct VSLQ *vslq, int n);
// Necessary because the field name is a go keyword.
static enum VSL_transaction_e
txtype(struct VSL_transaction *tx)
{
return tx->type;
}
// The rest are necessary due to the use of macros.
static inline int
slt_max()
{
return SLT__MAX;
}
static inline unsigned
vxid(struct VSL_cursor *c)
{
return (VSL_ID(c->rec.ptr));
}
static inline enum VSL_tag_e
tag(struct VSL_cursor *c)
{
return (VSL_TAG(c->rec.ptr));
}
static inline const char *
cdata(struct VSL_cursor *c)
{
return (VSL_CDATA(c->rec.ptr));
}
static inline int
len(struct VSL_cursor *c)
{
// Subtracting one because Go doesn't need the terminating null.
return (VSL_LEN(c->rec.ptr) - 1);
}
static inline int
client(struct VSL_cursor *c)
{
return (VSL_CLIENT(c->rec.ptr));
}
static inline int
backend(struct VSL_cursor *c)
{
return (VSL_BACKEND(c->rec.ptr));
}
static inline int
binary(enum VSL_tag_e tag)
{
return (VSL_tagflags[tag] & SLT_F_BINARY);
}
static inline int
unsafe(enum VSL_tag_e tag)
{
return (VSL_tagflags[tag] & SLT_F_UNSAFE);
}
#endif
/*-
* Copyright (c) 2018 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package log
import (
"bufio"
"errors"
"os"
"regexp"
"strconv"
"testing"
)
const (
testFile = "testdata/bin.log"
vxidLog = "testdata/vxid.log"
failPath = "ifAFileWithThisNameReallyExistsThenTestsFail"
)
func TestCheckData(t *testing.T) {
files := []string{testFile, vxidLog}
for _, file := range files {
_, err := os.Stat(file)
if err != nil {
t.Fatal("Cannot stat " + file + ": " + err.Error())
}
}
}
func TestNewRelease(t *testing.T) {
l := New()
defer l.Release()
if l == nil {
t.Fatal("New() returned nil")
}
}
func TestAttachFile(t *testing.T) {
l := New()
defer l.Release()
err := l.AttachFile(failPath)
if err == nil {
t.Error("Expected AttachFile() to fail for " + failPath)
}
err = l.AttachFile(testFile)
if err != nil {
t.Fatal("Cannot attach to " + testFile + ": " + err.Error())
}
}
type testRec struct {
vxid int
tag string
rectype rune
payload string
}
type testTx struct {
level uint
vxid uint32
txtype string
recs []*testRec
}
var (
txType2string = map[TxType]string{
TxUnknown: "Unknown",
Sess: "Session",
Req: "Request",
BeReq: "BeReq",
}
txline = regexp.MustCompile(`^(\*+)\s+<<\s+(\w+)\s+>>\s+(\d+)`)
recline = regexp.MustCompile(`^-+\s+(\d+)\s+(\w+)\s+([b|c|-])\s+(.*)$`)
)
func scrapeLog(file string) ([]*testTx, error) {
var txn []*testTx
f, err := os.Open(file)
if err != nil {
return nil, err
}
lines := bufio.NewScanner(f)
TX:
for lines.Scan() {
flds := txline.FindStringSubmatch(lines.Text())
if flds == nil {
return nil, errors.New("Cannot parse tx line: " +
lines.Text())
}
txVxid, err := strconv.Atoi(flds[3])
if err != nil {
return nil, errors.New("Cannot parse vxid " +
flds[4] + " in tx line: " + lines.Text())
}
tx := new(testTx)
tx.vxid = uint32(txVxid)
// NB: this works only for levels up to 3
tx.level = uint(len(flds[1]))
tx.txtype = flds[2]
for lines.Scan() {
// XXX: currently does not work for grouped txn
if lines.Text() == "" {
txn = append(txn, tx)
continue TX
}
flds = recline.FindStringSubmatch(lines.Text())
if flds == nil {
return nil, errors.New("Cannot parse record: " +
lines.Text())
}
rec := new(testRec)
rec.vxid, err = strconv.Atoi(flds[1])
if err != nil {
return nil, errors.New("Cannot parse vxid " +
flds[1] + " in rec line: " +
lines.Text())
}
rec.tag = flds[2]
rec.rectype = rune(flds[3][0])
rec.payload = flds[4]
tx.recs = append(tx.recs, rec)
}
}
return txn, nil
}
func TestDefaultRead(t *testing.T) {
expTxn, err := scrapeLog(vxidLog)
if err != nil {
t.Fatal(vxidLog + ": " + err.Error())
}
l := New()
defer l.Release()
err = l.AttachFile(testFile)
if err != nil {
t.Fatal("Cannot attach to " + testFile + ": " + err.Error())
}
txChan := make(chan []*Transaction, 50)
statusChan := make(chan *RWStatus)
err = l.Read(txChan, statusChan)
if err != nil {
t.Fatal("Read(): " + err.Error())
}
txi := 0
for txn := range txChan {
for _, txp := range txn {
if txi+1 > len(expTxn) {
t.Fatalf("too many transactions expected=%v "+
"got=%v",
len(expTxn), txi+1)
}
tx := *txp
expTx := expTxn[txi]
if tx.Level != expTx.level {
t.Errorf("tx Level expected=%v got=%v",
expTx.level, tx.Level)
}
if tx.VXID != expTx.vxid {
t.Errorf("tx VXID expected=%v got=%v",
expTx.vxid, tx.VXID)
}
if txType2string[tx.Type] != expTx.txtype {
t.Errorf("tx Type expected=%v got=%v",
expTx.txtype, txType2string[tx.Type])
}
// XXX: check pxvid and reason from Begin record
if len(tx.Records) != len(expTx.recs) {
t.Errorf("tx number of records expected=%v "+
"got %v", len(expTx.recs),
len(tx.Records))
continue
}
reci := 0
for _, rec := range tx.Records {
expRec := expTx.recs[reci]
if rec.VXID != uint(expRec.vxid) {
t.Errorf("rec vxid expected=%v got=%v",
expRec.vxid, rec.VXID)
}
if Tags[rec.Tag] != expRec.tag {
t.Errorf("rec tag expected=%v got=%v",
expRec.tag, rec.Tag)
}
if rune(rec.Type) != expRec.rectype {
t.Errorf("rec type expected=%v got=%v",
expRec.rectype, rune(rec.Type))
}
if len(rec.Payload) != len(expRec.payload) {
t.Errorf("rec payload length "+
"expected=%v got=%v",
len(expRec.payload),
len(rec.Payload))
}
if rec.Payload != expRec.payload {
t.Errorf("rec payload expected='%v' "+
"got='%v'",
expRec.payload, rec.Payload)
}
reci++
}
txi++
}
}
if txi < len(expTxn) {
t.Errorf("not enough transactions expected=%v got=%v",
len(expTxn), txi)
}
status := <-statusChan
if status.Status != StatusType(EOF) {
t.Errorf("expected EOF status got: %v", status.Error())
}
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment